The Problem Developers working with 3D Gaussian splats need a reliable way to ingest many proprietary formats (PLY, SOG, KSPLAT, etc.), apply geometric or statistical transforms, and export to downstream pipelines (GLB, CSV, voxel octrees). Existing tools are either single‑purpose scripts or closed‑source binaries, making integration and automation difficult.

What This Does splat‑transform supplies both a CLI (src/cli/index.ts) and a library (src/lib/**) that read, manipulate, and write splat data. Core functionality lives in the data‑table layer (src/lib/data-table/*.ts) for column‑wise Gaussian storage, the voxel pipeline (src/lib/voxel/*.ts) for collision meshes, and the GPU helpers (src/lib/gpu/*.ts) for optional WebGPU acceleration. The src/lib/writers/ folder contains format‑specific exporters, while src/lib/readers/ parses the supported inputs. The project is pure TypeScript, built with npm (package.json) and bundled via Rollup (rollup.config.mjs).

How It Is Wired Execution starts at the CLI entry point src/cli/index.tsmain (line 675). main parses arguments (parseArguments), builds a DataTable via src/lib/read.ts → format‑specific readers (e.g., read-ksplat.ts, read-ply.ts). The resulting table is passed through a pipeline of actions (transformColumns, simplifyGaussians, decimate, etc.), each heavily dependent on src/lib/data-table/index.ts – the hub module imported by 39 other files. After processing, the CLI calls the appropriate writer (src/lib/writers/write-ply.ts, write-glb.ts, etc.) which eventually invokes fs.writeFile (via src/lib/io/write/file-system.ts). A single cryptographic call (randomBytes(6).toString) appears in src/cli/node-file-system.ts when generating temporary filenames.

Key call‑graph hotspots:

  • getColumnByName is invoked from 30 locations (e.g., simplifyGaussians, decompressPly).
  • slot (voxel grid) is called from 22 places.
  • marchingCubes (mesh generation) reaches src/lib/mesh/marching-cubes.ts and calls getVertex 12 times.

Circular imports involve src/lib/data-table/index.ts, src/lib/utils/index.ts, and src/lib/data-table/data-table.ts (15 modules in cycles). The most massive source files exceed 1 300 lines (marching-cubes.ts, sparse-octree.ts, decimate.ts) and contain deep nesting (max indentation depth 7). These patterns inflate the blast radius of any change.

How To Use It

# Install globally (CLI) or locally (library)
npm install -g @playcanvas/splat-transform
# or
npm install @playcanvas/splat-transform

# Basic conversion: input → output with optional actions
splat-transform input.splat -t 1,0,0 -s 0.5 output.glb

The CLI expects a list of input files followed by actions and a final output file. Actions are parsed in src/cli/index.ts (-t, -r, -s, -H, etc.). For programmatic use, import the library:

import { read, write, transform } from '@playcanvas/splat-transform';
const table = await read('scene.ply');
const transformed = transform(table, { scale: 0.8 });
await write(transformed, 'scene.sog');

No additional configuration files are required; the tool works in Node.js and browsers out‑of‑the‑box.

Real‑World Use A game‑engine build pipeline can invoke the CLI to generate a low‑poly collision octree from artist‑authored PLY splats:

splat-transform assets/hero.ply --filter-harmonics 2 --decimate 0.3 hero.voxel.json

The resulting hero.voxel.json feeds directly into PlayCanvas physics, avoiding a separate conversion step.

Code Health & Issues

Measured findings (static analysis)

  • High – Import cycles (15 modules): src/lib/data-table/index.tssrc/lib/utils/index.ts. Break cycles by extracting shared types or using lazy imports.
  • High – Deep nesting (27 files): e.g., sparse-voxel-grid.ts (indent 7). Refactor with guard clauses.
  • High – Hub module (5 files): data-table/index.ts is a stability hotspot; keep it minimal.
  • High – Oversized files (4 files): marching-cubes.ts (1 391 LOC). Split into focused sub‑modules.
  • High – Duplicated code (≈169 repeated 6‑line blocks) across generators and file‑system helpers; consolidate into shared utilities.
  • Medium – High branching density (8 files); consider strategy tables.

CI/CD health audit

  • HIGH – GitHub Actions pinned to tags only (softprops/action-gh-release@v3). Replace with commit SHA to avoid supply‑chain risk.
  • HIGH – CI workflow does not run the test suite. Add a npm test step.
  • MEDIUM – No explicit permissions for GITHUB_TOKEN. Declare least‑privilege (contents: read).
  • MEDIUM – No dependency‑vulnerability scan. Add dependency-review-action or osv-scanner.
  • MEDIUM – Checkout retains credentials; set persist-credentials: false.
  • LOW – No job timeouts; add timeout-minutes.
  • LOW – Missing editor/formatter config (.editorconfig, .gitattributes). Add them to enforce consistent style.

The Bottom Line splat‑transform delivers a comprehensive, TypeScript‑native pipeline for Gaussian splat conversion and manipulation, with solid test coverage and a clear CLI. However, the codebase suffers from import cycles, large monolithic files, and several CI hygiene gaps that increase maintenance risk. It is suitable for teams comfortable with TypeScript who can allocate effort to refactor hot‑spot modules and tighten the CI configuration.