Skip to content

IO Module API Reference

This document captures every public interface exposed by the IO module. It mirrors the SparkJS tone: introduce the concept, show signatures, and explain how it fits into the broader Gaussian Splatting pipeline.

Table of contents


Core interfaces

DataSource

Canonical contract for any data source that provides 3D model metadata.

interface DataSource {
  bbox(): { min: [number, number, number]; max: [number, number, number] };
  center?: [number, number, number];
  up?: [number, number, number] | null;
  kernelSize?: number;
  mipSplatting?: boolean;
  backgroundColor?: [number, number, number];
}

GaussianDataSource

Specializes DataSource for Gaussian splats, independent of the original file format.

interface GaussianDataSource extends DataSource {
  gaussianBuffer(): ArrayBuffer;
  shCoefsBuffer(): ArrayBuffer;
  numPoints(): number;
  shDegree(): number;
}
  • gaussianBuffer() – Packed splat parameters in half-floats (10 uint16 values per point).
  • shCoefsBuffer() – Interleaved spherical harmonics coefficients (two f16 stored in each uint32).
  • numPoints() – Total splat count.
  • shDegree() – Spherical harmonics degree; (degree + 1)^2 coefficients per channel.

ThreeJSDataSource

Adapter for loaders that surface Three.js objects alongside model data.

interface ThreeJSDataSource extends DataSource {
  object3D(): any;            // THREE.Object3D
  modelType(): string;
}

ILoader<T>

Generic file loader contract.

interface ILoader<T extends DataSource = DataSource> {
  loadFile(file: File, options?: LoadingOptions): Promise<T>;
  loadUrl(url: string, options?: LoadingOptions): Promise<T>;
  loadBuffer(buffer: ArrayBuffer, options?: LoadingOptions): Promise<T>;
  canHandle(filename: string, mimeType?: string): boolean;
  getSupportedExtensions(): string[];
}

LoadingOptions typically include progress callbacks and cancellation signals.

LoaderRegistry

Dynamic registry that maps file extensions to loaders.

interface LoaderRegistry {
  register<T extends DataSource>(loader: ILoader<T>, extensions: string[]): void;
  getLoader(filename: string, mimeType?: string): ILoader | null;
  getAllSupportedExtensions(): string[];
}

Universal loader

Entry points

function createUniversalLoader(): UniversalLoader;
const defaultLoader: UniversalLoader;
  • createUniversalLoader() – Builds an isolated registry instance.
  • defaultLoader – Shared singleton used by the App layer.

UniversalLoader surface

class UniversalLoader implements ILoader, LoaderRegistry {
  constructor();

  // ILoader interface
  loadFile(file: File, options?: LoadingOptions): Promise<DataSource>;
  loadUrl(url: string, options?: LoadingOptions): Promise<DataSource>;
  loadBuffer(buffer: ArrayBuffer, options?: LoadingOptions): Promise<DataSource>;
  canHandle(filename: string, mimeType?: string, options?: { isGaussian?: boolean }): boolean;
  getSupportedExtensions(): string[];

  // LoaderRegistry interface
  register<T extends DataSource>(loader: ILoader<T>, extensions: string[], type: LoaderType): void;
  getLoader(filename: string, mimeType?: string, options?: { isGaussian?: boolean }): ILoader | null;
  getAllSupportedExtensions(): string[];

  // Additional methods
  async getLoaderForFile(file: File, mimeType?: string): Promise<ILoader | null>;
}

LoaderType Enum:

enum LoaderType {
  GAUSSIAN = 'gaussian',
  THREE = 'three'
}

Format detection pipeline

  1. Inspect file extension/MIME type.
  2. Check explicit options.isGaussian hint.
  3. For .ply files, read header to detect 3DGS properties.
  4. Check magic bytes for compressed formats (GZIP, ZIP, KSPL).
  5. Locate the first registered loader that claims support.
  6. Stream data with progress updates ({ stage, progress, message? }).
  7. Normalize results into a DataSource.

Progress reporting

LoadingOptions accepts:

interface LoadingOptions {
  signal?: AbortSignal;
  onProgress?: (progress: LoadingProgress) => void;
  debug?: boolean;
  isGaussian?: boolean;  // Explicit format hint
}

interface LoadingProgress {
  stage: 'fetch' | 'parse' | 'pack' | string;
  progress: number;          // 0..1
  message?: string;
}

Gaussian format loaders

PLYLoader

Handles both ASCII and binary PLY splats.

class PLYLoader implements ILoader<PLYGaussianData> {
  loadFile(file: File, options?: LoadingOptions): Promise<PLYGaussianData>;
  loadUrl(url: string, options?: LoadingOptions): Promise<PLYGaussianData>;
  loadBuffer(buffer: ArrayBuffer, options?: LoadingOptions): Promise<PLYGaussianData>;
  canHandle(filename: string): boolean;
  getSupportedExtensions(): string[]; // ['.ply']
}

Key behaviours:

  • Auto-detect ASCII vs binary payloads (little-endian and big-endian).
  • Parses Gaussian-specific vertex properties (position, opacity, SH coefficients, covariance).
  • Emits informative errors when headers or properties are missing.
  • Streams large files to avoid blocking the main thread.
  • Performs normalization, quaternion conversion, and SH packing.

CompressedPLYLoader

Handles compressed PLY files.

class CompressedPLYLoader implements ILoader<PLYGaussianData> {
  loadFile(file: File, options?: LoadingOptions): Promise<PLYGaussianData>;
  loadUrl(url: string, options?: LoadingOptions): Promise<PLYGaussianData>;
  loadBuffer(buffer: ArrayBuffer, options?: LoadingOptions): Promise<PLYGaussianData>;
  canHandle(filename: string): boolean;
  getSupportedExtensions(): string[]; // ['.compressed.ply']
}

Key behaviours:

  • Decompresses before parsing with standard PLY loader.
  • Supports both file and URL loading.

SPZLoader

Handles SPZ (GZIP-based container) format.

class SPZLoader implements ILoader<PLYGaussianData> {
  loadFile(file: File, options?: LoadingOptions): Promise<PLYGaussianData>;
  loadUrl(url: string, options?: LoadingOptions): Promise<PLYGaussianData>;
  loadBuffer(buffer: ArrayBuffer, options?: LoadingOptions): Promise<PLYGaussianData>;
  canHandle(filename: string): boolean;
  getSupportedExtensions(): string[]; // ['.spz']
}

Key behaviours:

  • GZIP-compressed container format.
  • Handles quantized positions/rotations.
  • Optimized for smaller file sizes.

KSplatLoader

Handles Luma AI's KSplat format.

class KSplatLoader implements ILoader<PLYGaussianData> {
  loadFile(file: File, options?: LoadingOptions): Promise<PLYGaussianData>;
  loadUrl(url: string, options?: LoadingOptions): Promise<PLYGaussianData>;
  loadBuffer(buffer: ArrayBuffer, options?: LoadingOptions): Promise<PLYGaussianData>;
  canHandle(filename: string): boolean;
  getSupportedExtensions(): string[]; // ['.ksplat']
}

Key behaviours:

  • Detects "KSPL" magic bytes (first 4 bytes).
  • Luma AI optimized block format.
  • Fast loading with minimal parsing overhead.

SplatLoader

Handles raw binary SPLAT format.

class SplatLoader implements ILoader<PLYGaussianData> {
  loadFile(file: File, options?: LoadingOptions): Promise<PLYGaussianData>;
  loadUrl(url: string, options?: LoadingOptions): Promise<PLYGaussianData>;
  loadBuffer(buffer: ArrayBuffer, options?: LoadingOptions): Promise<PLYGaussianData>;
  canHandle(filename: string): boolean;
  getSupportedExtensions(): string[]; // ['.splat']
}

Key behaviours:

  • Raw binary dump format (32-byte stride per point).
  • Extremely fast loading (no parsing overhead).
  • Format: [x, y, z, r, g, b, a, rot_0, rot_1, rot_2, rot_3, scale_0, scale_1, scale_2] (all float32).

SOGLoader

Handles SuperOrdered Gaussians format.

class SOGLoader implements ILoader<PLYGaussianData> {
  loadFile(file: File, options?: LoadingOptions): Promise<PLYGaussianData>;
  loadUrl(url: string, options?: LoadingOptions): Promise<PLYGaussianData>;
  loadBuffer(buffer: ArrayBuffer, options?: LoadingOptions): Promise<PLYGaussianData>;
  canHandle(filename: string): boolean;
  getSupportedExtensions(): string[]; // ['.sog']
}

Key behaviours:

  • SuperOrdered Gaussians format.
  • Supports both Raw and ZIP-compressed variants.
  • Detects ZIP magic bytes (0x504b0304).
  • Handles hierarchical Gaussian organization.

UniversalGaussianLoader

Specialized loader that only handles Gaussian Splatting formats.

class UniversalGaussianLoader implements ILoader<PLYGaussianData> {
  constructor();

  loadFile(file: File, options?: LoadingOptions): Promise<PLYGaussianData>;
  loadUrl(url: string, options?: LoadingOptions): Promise<PLYGaussianData>;
  loadBuffer(buffer: ArrayBuffer, options?: LoadingOptions): Promise<PLYGaussianData>;
  canHandle(filename: string, mimeType?: string): boolean;
  getSupportedExtensions(): string[];
}

Key behaviours:

  • Single-purpose: Gaussian formats only.
  • Simpler API surface.
  • Faster format detection (no Three.js registry lookup).
  • Internally manages: PLY, SPZ, KSplat, SPLAT, SOG, Compressed PLY.

Three.js adapters

ThreeJSModelData

Wrapper class that implements ThreeJSDataSource interface.

class ThreeJSModelData implements ThreeJSDataSource {
  constructor(object3D: THREE.Object3D, modelType: string = 'unknown');

  object3D(): THREE.Object3D;
  modelType(): string;
  bbox(): { min: [number, number, number]; max: [number, number, number] };
}

GLTFLoaderAdapter

Adapter for GLTF/GLB format.

class GLTFLoaderAdapter extends ThreeJSLoaderAdapter<THREE.Group> {
  constructor();
  getSupportedExtensions(): string[]; // ['.gltf', '.glb']
  // ... implements ILoader<ThreeJSModelData>
}

Key behaviours:

  • Wraps THREE.GLTFLoader.
  • Preserves GLTF materials.
  • Automatically applies shadow settings.
  • Supports progress reporting.

OBJLoaderAdapter

Adapter for OBJ format.

class OBJLoaderAdapter extends ThreeJSLoaderAdapter<THREE.Group> {
  constructor();
  getSupportedExtensions(): string[]; // ['.obj']
  // ... implements ILoader<ThreeJSModelData>
}

Key behaviours:

  • Wraps THREE.OBJLoader.
  • Supports MTL material files.
  • Applies shadow settings and fallback materials.

FBXLoaderAdapter

Adapter for FBX format.

class FBXLoaderAdapter extends ThreeJSLoaderAdapter<THREE.Group> {
  constructor();
  getSupportedExtensions(): string[]; // ['.fbx']
  // ... implements ILoader<ThreeJSModelData>
}

Key behaviours:

  • Wraps THREE.FBXLoader.
  • Preserves FBX materials.
  • Applies shadow settings.

STLLoaderAdapter

Adapter for STL format.

class STLLoaderAdapter extends ThreeJSLoaderAdapter<THREE.Mesh> {
  constructor();
  getSupportedExtensions(): string[]; // ['.stl']
  // ... implements ILoader<ThreeJSModelData>
}

Key behaviours:

  • Wraps THREE.STLLoader.
  • Creates mesh with fallback material.
  • Applies shadow settings.

ThreeJSPLYLoaderAdapter

Adapter for traditional mesh PLY format.

class ThreeJSPLYLoaderAdapter extends ThreeJSLoaderAdapter<THREE.Mesh> {
  constructor();
  getSupportedExtensions(): string[]; // ['.ply']
  // ... implements ILoader<ThreeJSModelData>
}

Key behaviours:

  • Wraps THREE.PLYLoader.
  • Used for PLY files that don't contain 3DGS properties.
  • Automatically detected when PLY header lacks 3DGS properties.

createThreeJSAdapters

Factory function that creates all Three.js adapters.

function createThreeJSAdapters(): ThreeJSLoaderAdapter<any>[];

Returns an array of all available Three.js loader adapters.


Data containers

PLYGaussianData

Concrete GaussianDataSource implementation returned by all Gaussian loaders.

class PLYGaussianData implements GaussianDataSource {
  constructor(args: {
    gaussianBuffer: ArrayBuffer;
    shBuffer: ArrayBuffer;
    numPoints: number;
    degree: number;
    bbox: { min: [number, number, number]; max: [number, number, number] };
    center?: [number, number, number];
    up?: [number, number, number] | null;
    kernelSize?: number;
    mipSplatting?: boolean;
    backgroundColor?: [number, number, number];
  });

  gaussianBuffer(): ArrayBuffer;
  shCoefsBuffer(): ArrayBuffer;
  numPoints(): number;
  shDegree(): number;
  bbox(): { min: [number, number, number]; max: [number, number, number] };
}

Format detection utilities

GaussianFormat enum

enum GaussianFormat {
  PLY = 'ply',
  SPZ = 'spz',
  KSPLAT = 'ksplat',
  SPLAT = 'splat',
  SOG = 'sog',
  COMPRESSED_PLY = 'compressed.ply'
}

detectGaussianFormat

Detects Gaussian format from filename.

function detectGaussianFormat(filename: string): GaussianFormat | null;

Returns: Format enum or null if not a recognized Gaussian format.

Example:

const format = detectGaussianFormat('model.spz'); // Returns GaussianFormat.SPZ

isGaussianFormat

Checks if filename has a supported Gaussian format.

function isGaussianFormat(filename: string): boolean;

Returns: true if filename ends with a supported Gaussian extension.

getSupportedGaussianFormats

Returns all supported Gaussian format extensions.

function getSupportedGaussianFormats(): string[];

Returns: ['.ply', '.spz', '.ksplat', '.splat', '.sog', '.compressed.ply']

isGaussianDataSource

Type guard to check if data source is Gaussian data.

function isGaussianDataSource(data: DataSource): data is GaussianDataSource;

Returns: Type predicate indicating if data is GaussianDataSource.

isThreeJSDataSource

Type guard to check if data source is Three.js model.

function isThreeJSDataSource(data: DataSource): data is ThreeJSDataSource;

Returns: Type predicate indicating if data is ThreeJSDataSource.


Scene saving

saveUnifiedScene

Saves scene structure and model files to a directory.

async function saveUnifiedScene(params: SaveUnifiedSceneParams): Promise<void>;

Parameters:

interface SaveUnifiedSceneParams {
  scenes: SaveUnifiedSceneSceneEntry[];
  folderHandle: FileSystemDirectoryHandle;
  meta?: any;
  cameraParams?: any;
  totalFrames?: number;
}

Scene Entry:

interface SaveUnifiedSceneSceneEntry {
  models: SaveUnifiedSceneModel[];
  keyframes?: SaveUnifiedSceneKeyframe[];
  view?: 'left' | 'right' | string;
  [k: string]: any;
}

Model:

interface SaveUnifiedSceneModel {
  id: string;
  name?: string;
  typeTag: string;
  trs: [number[], number[], number[]];
  type?: string;
  gaussianParams?: any;
  cameraParams?: any;
  params?: Record<string, any>;
  originFile?: File | Blob | FileSystemFileHandle;
  assetName?: string;
}

Keyframe:

interface SaveUnifiedSceneKeyframe {
  objectId: string;
  frame: number;
  trs: [number[], number[], number[]];
  gaussianParams?: any;
  cameraParams?: any;
}

Key behaviours:

  • Verifies folder handle permissions before saving.
  • Clears target folder contents before writing.
  • Copies all model files (deduplicated by name).
  • Generates scene.json with scene structure.
  • Handles FileSystem API errors gracefully.

Example:

await saveUnifiedScene({
  scenes: [{
    models: [{
      id: 'model-1',
      name: 'MyModel.ply',
      typeTag: 'fileModel',
      trs: [[0, 0, 0], [0, 0, 0, 1], [1, 1, 1]],
      originFile: fileHandle,
      assetName: 'MyModel.ply'
    }],
    keyframes: [{
      objectId: 'model-1',
      frame: 0,
      trs: [[0, 0, 0], [0, 0, 0, 1], [1, 1, 1]]
    }]
  }],
  folderHandle: directoryHandle,
  meta: { createdAt: new Date().toISOString() }
});

Type definitions

LoadingOptions

interface LoadingOptions {
  onProgress?: (progress: LoadingProgress) => void;
  signal?: AbortSignal;
  debug?: boolean;
  isGaussian?: boolean;  // Explicit format hint
}

LoadingProgress

interface LoadingProgress {
  stage: 'fetch' | 'parse' | 'pack' | string;
  progress: number;          // 0..1
  message?: string;
}

LoaderType

enum LoaderType {
  GAUSSIAN = 'gaussian',
  THREE = 'three'
}

Error handling

The IO module surfaces typed errors so callers can provide actionable feedback.

Error Description Recommended action
UnsupportedFormatError No loader accepted the file extension/MIME type. Prompt the user to pick a supported format or install an extension loader.
MalformedPLYHeaderError Header missing required properties. Verify the asset was exported with Visionary / Spark-compatible tooling.
PLYStreamError Binary payload ended unexpectedly. Suggest re-downloading/re-exporting the asset.
AbortError Loading aborted via AbortController. Silent cancellation; typically user initiated.
FolderHandleError FileSystem folder handle invalid or permission denied. Request new folder handle or check permissions.

All errors extend IOError, which adds stage?: ProgressStage for richer telemetry.

class IOError extends Error {
  constructor(message: string, options?: { stage?: ProgressStage; cause?: unknown });
  stage?: ProgressStage;
}

Integration checklist

  • Use defaultLoader inside the App module; it already registers all supported formats.
  • Register custom loaders early during bootstrap so they participate in detection.
  • Always supply onProgress when loading large assets to keep the UI responsive.
  • Use isGaussian option explicitly when format is ambiguous (e.g., .ply files).
  • Share helper functions (packing, bounds, metadata extraction) with preprocessing to avoid duplicate maths.
  • Handle AbortSignal for user-initiated cancellations.
  • Use type guards (isGaussianDataSource, isThreeJSDataSource) for runtime type checking.