ply2splat 0.3.1

A Rust crate for processing Gaussian Splatting PLY and SPLAT files
Documentation

ply2splat

Crates.io docs.rs PyPI npm License: MIT

A Rust crate and CLI tool for converting Gaussian Splatting .ply files to the .splat format.

Available on crates.io for Rust, PyPI for Python, and npm for JavaScript/TypeScript.

Workspace Architecture

This repository is organized as a Cargo workspace:

.                      # Core library (ply2splat) and CLI
├── bindings/
│   ├── ply2splat-wasm/    # WASM bindings for browser/Node.js
│   ├── ply2splat-napi/    # Native Node.js bindings via NAPI-RS
│   └── ply2splat-python/  # Python bindings via PyO3
└── packages/
    └── ply2splat/         # Unified npm package (WASM + optional native)

Features

  • High Performance: Utilizes parallel processing (via rayon) for conversion and sorting.
  • Fast I/O: Uses zero-copy serialization and large buffers for maximum throughput.
  • Correctness: Implements the standard conversion logic including Spherical Harmonics (SH) to color conversion and geometric transformations.
  • Python Bindings: Use the library directly from Python via PyO3.
  • WebAssembly Support: Run in browsers and Node.js via the npm package.
  • Native Node.js Bindings: For maximum performance via NAPI-RS.

Installation

Rust Crate

Add ply2splat to your Cargo.toml:

[dependencies]
ply2splat = "0.2"

CLI

Install the CLI tool directly from crates.io:

cargo install ply2splat

Or build from source:

git clone https://github.com/bastikohn/ply2splat.git
cd ply2splat
cargo build --release

The binary will be available at target/release/ply2splat.

Python Package

Install from PyPI:

pip install ply2splat

Or install from source using maturin:

pip install maturin
git clone https://github.com/bastikohn/ply2splat.git
cd ply2splat
maturin develop --release

Or build a wheel:

maturin build --release
pip install target/wheels/ply2splat-*.whl

npm Package (WebAssembly)

Install from npm:

npm install ply2splat

Usage

CLI

ply2splat --input input.ply --output output.splat

Python

import ply2splat

# Convert a PLY file to SPLAT format
count = ply2splat.convert("input.ply", "output.splat")
print(f"Converted {count} splats")

# Convert without sorting (faster, but may affect rendering quality)
count = ply2splat.convert("input.ply", "output.splat", sort=False)

# Load PLY file and access individual splats
data = ply2splat.load_ply_file("input.ply")
print(f"Loaded {len(data)} splats")

for splat in data:
    print(f"Position: {splat.position}")
    print(f"Scale: {splat.scale}")
    print(f"Color (RGBA): {splat.color}")
    print(f"Rotation: {splat.rotation}")

# Access splats by index
first_splat = data[0]
last_splat = data[-1]

# Load existing SPLAT file
data = ply2splat.load_splat_file("output.splat")
print(f"Loaded {len(data)} splats from SPLAT file")

# Get raw bytes for custom processing
raw_bytes = data.to_bytes()

# Load and convert to bytes (for in-memory processing)
data, count = ply2splat.load_and_convert("input.ply")
print(f"Loaded {count} splats, {len(data)} bytes")

JavaScript/TypeScript (Browser/Node.js)

The npm package provides full TypeScript support with helper functions for working with various input types.

Browser Usage

import { init, convertFromFile, convertFromUrl, downloadSplat } from 'ply2splat';

// Initialize the WASM module
await init();

// Convert from a File input
const fileInput = document.querySelector('input[type="file"]') as HTMLInputElement;
fileInput.addEventListener('change', async (e) => {
  const file = fileInput.files![0];
  const result = await convertFromFile(file);
  console.log(`Converted ${result.count} splats`);
  
  // Get typed Splat objects
  const splats = result.toSplats();
  console.log(splats[0].position);  // [x, y, z]
  
  // Download the result
  downloadSplat(result.data, 'output.splat');
});

// Convert from a URL
const result = await convertFromUrl('https://example.com/model.ply');

Node.js Usage

import { init, convertFromBuffer } from 'ply2splat';
import { readFileSync } from 'fs';

// Initialize the WASM module
await init();

// Convert from a Node.js Buffer
const plyBuffer = readFileSync('model.ply');
const result = convertFromBuffer(plyBuffer);
console.log(`Converted ${result.count} splats`);

// Get typed splat data
const splats = result.toSplats();

The package includes full TypeScript definitions. See the API documentation for detailed type information and all available helper functions.

Development

Requirements

  • Rust (latest stable)
  • Nix (optional, for reproducible environment)
  • wasm-pack (for WASM builds)

Running Tests

# Test the entire workspace
cargo test --workspace

# Test a specific crate
cargo test -p ply2splat

Building WASM

# Install wasm-pack
cargo install wasm-pack

# Build for web (browsers)
wasm-pack build bindings/ply2splat-wasm --target web --out-dir ../../packages/ply2splat/wasm

# Build for bundlers (webpack, etc.)
wasm-pack build bindings/ply2splat-wasm --target bundler --out-dir ../../packages/ply2splat/wasm

Building the npm Package

# Build WASM first
wasm-pack build bindings/ply2splat-wasm --target web --out-dir ../../packages/ply2splat/wasm

# Build TypeScript
cd packages/ply2splat
npm install
npm run build

Fuzzing

The crate includes fuzzing targets to ensure stability against malformed inputs.

# Install cargo-fuzz
cargo install cargo-fuzz

# Run fuzzing target
cargo fuzz run fuzz_conversion

Development Environment

This project supports both Nix and Devcontainers for a reproducible development environment.

  • Nix: nix develop will enter a shell with Rust and dependencies configured.
  • Devcontainer: Open the folder in VS Code and accept the prompt to reopen in container.

License

MIT