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
- Universal loader
- Gaussian format loaders
- Three.js adapters
- Data containers
- Format detection utilities
- Scene saving
- Type definitions
- Error handling
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 (10uint16values per point).shCoefsBuffer()– Interleaved spherical harmonics coefficients (two f16 stored in eachuint32).numPoints()– Total splat count.shDegree()– Spherical harmonics degree;(degree + 1)^2coefficients 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
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:
Format detection pipeline
- Inspect file extension/MIME type.
- Check explicit
options.isGaussianhint. - For
.plyfiles, read header to detect 3DGS properties. - Check magic bytes for compressed formats (GZIP, ZIP, KSPL).
- Locate the first registered loader that claims support.
- Stream data with progress updates (
{ stage, progress, message? }). - 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.
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.
Returns: Format enum or null if not a recognized Gaussian format.
Example:
isGaussianFormat
Checks if filename has a supported Gaussian format.
Returns: true if filename ends with a supported Gaussian extension.
getSupportedGaussianFormats
Returns all supported Gaussian format extensions.
Returns: ['.ply', '.spz', '.ksplat', '.splat', '.sog', '.compressed.ply']
isGaussianDataSource
Type guard to check if data source is Gaussian data.
Returns: Type predicate indicating if data is GaussianDataSource.
isThreeJSDataSource
Type guard to check if data source is Three.js model.
Returns: Type predicate indicating if data is ThreeJSDataSource.
Scene saving
saveUnifiedScene
Saves scene structure and model files to a directory.
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.jsonwith 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
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
defaultLoaderinside the App module; it already registers all supported formats. - Register custom loaders early during bootstrap so they participate in detection.
- Always supply
onProgresswhen loading large assets to keep the UI responsive. - Use
isGaussianoption explicitly when format is ambiguous (e.g.,.plyfiles). - Share helper functions (packing, bounds, metadata extraction) with preprocessing to avoid duplicate maths.
- Handle
AbortSignalfor user-initiated cancellations. - Use type guards (
isGaussianDataSource,isThreeJSDataSource) for runtime type checking.