Skip to content

IO Module

The IO Module serves as the Unified Data Ingestion Layer for Visionary. It handles file loading and data parsing for multiple 3D Gaussian Splatting formats and standard 3D mesh formats. It provides a flexible, extensible architecture for loading various file formats and converting them into GPU-ready data structures.

Overview

The IO module is the entry point for all data loading operations in the 3D Gaussian Splatting pipeline. It transforms raw file data into structured formats optimized for WebGPU rendering, abstracting the complexity of various file formats into a consistent memory layout (DataSource) that the application can consume without knowing the underlying file structure.

Key Features

  • Universal File Loading: Automatic format detection and delegation to appropriate loaders
  • Multiple Gaussian Formats: Supports PLY, SPZ, KSplat, SPLAT, SOG, and Compressed PLY
  • Three.js Mesh Support: Handles FBX, GLTF, OBJ, STL, and Mesh PLY through adapters
  • Intelligent Routing: Automatically selects the correct loader based on file extensions, MIME types, or binary "Magic Bytes" sniffing
  • PLY Disambiguation: Automatically detects if a PLY file is 3DGS or mesh format by checking header properties
  • Format Detection: Helper functions for format identification (detectGaussianFormat, isGaussianFormat)
  • Progress Reporting: Detailed loading progress with stage-specific feedback
  • Memory Optimization: Efficient data transformation with half-precision packing
  • Extensible Architecture: Plugin-style loader registration system with dual registry (Gaussian and Three.js)
  • Error Handling: Comprehensive validation and descriptive error messages
  • Scene Saving: Unified scene export functionality (saveUnifiedScene)

Core Concepts

  • Data Sources: Standardized interface (DataSource, GaussianDataSource, ThreeJSDataSource) for data regardless of source format
  • Loader Registry: Dynamic registration system for different file format parsers (Gaussian and Three.js)
  • Dual Registry System: Separate registries for Gaussian Splatting formats and Three.js mesh formats
  • Format Detection: Automatic format identification via extension, MIME type, or magic bytes
  • Progress Callbacks: User feedback during long-running loading operations
  • Buffer Management: Efficient CPU-to-GPU data transfer preparation
  • Type Guards: Safe type checking (isGaussianDataSource, isThreeJSDataSource)

Quick Start

Basic File Loading (Universal Loader)

import { defaultLoader } from 'src/io';

// Load from file input - automatically detects format
const fileInput = document.querySelector('input[type="file"]');
fileInput.addEventListener('change', async (event) => {
  const file = event.target.files[0];

  try {
    const data = await defaultLoader.loadFile(file, {
      onProgress: (progress) => {
        console.log(`${progress.stage}: ${progress.progress * 100}%`);
      }
    });

    // Check if it's Gaussian data
    if (isGaussianDataSource(data)) {
      console.log(`Loaded ${data.numPoints()} points`);
      console.log(`SH degree: ${data.shDegree()}`);
    } else if (isThreeJSDataSource(data)) {
      console.log(`Loaded ${data.modelType()} model`);
    }
  } catch (error) {
    console.error('Loading failed:', error);
  }
});

Loading Different Formats

import { defaultLoader, detectGaussianFormat, isGaussianFormat } from 'src/io';

// Detect format from filename
const format = detectGaussianFormat('model.spz');
console.log(`Format: ${format}`); // 'spz'

// Check if file is Gaussian format
if (isGaussianFormat('model.ply')) {
  const data = await defaultLoader.loadFile(file);
}

// Load specific format
import { SPZLoader } from 'src/io';
const spzLoader = new SPZLoader();
const data = await spzLoader.loadUrl('/models/scene.spz');

Loading from URL

import { defaultLoader } from 'src/io';

const data = await defaultLoader.loadUrl('/models/scene.ply', {
  isGaussian: true, // Explicitly specify if ambiguous
  onProgress: ({ stage, progress, message }) => {
    updateProgressBar(progress);
    setStatusText(`${stage}: ${message || ''}`);
  }
});

Custom Loader Registration

import { createUniversalLoader, LoaderType } from 'src/io';

const loader = createUniversalLoader();

// Register custom Gaussian format loader
class CustomGaussianLoader implements ILoader<GaussianDataSource> {
  // ... implementation
}

loader.register(new CustomGaussianLoader(), ['.custom'], LoaderType.GAUSSIAN);

// Register custom Three.js adapter
loader.register(new CustomThreeJSAdapter(), ['.custom'], LoaderType.THREE);

Scene Saving

import { saveUnifiedScene } from 'src/io/unified-scene-saver';

// Save scene with models and keyframes
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(),
    author: 'User'
  }
});

Module Structure

src/io/
├── index.ts                      # Interfaces, types, and exports
├── universal_loader.ts           # Universal loader (Gaussian + Three.js)
├── universal_gaussian_loader.ts  # Gaussian-only loader
├── ply_loader.ts                 # PLY format implementation
├── spz_loader.ts                 # SPZ format implementation
├── ksplat_loader.ts              # KSplat format implementation
├── splat_loader.ts               # SPLAT format implementation
├── sog_loader.ts                 # SOG format implementation
├── compressed_ply_loader.ts      # Compressed PLY implementation
├── GaussianData.ts               # PLYGaussianData class
├── threejs_adapters.ts           # Three.js mesh format adapters
└── unified-scene-saver.ts        # Scene saving functionality

Data Flow

  1. File Input → Universal loader detects format
  2. Format Detection → Appropriate loader selected (Gaussian or Three.js registry)
  3. PLY Disambiguation → For .ply files, header is checked to determine if 3DGS or mesh
  4. Parsing → Raw data parsed with progress reporting
  5. Processing → Data transformed to GPU format
  6. OutputGaussianDataSource or ThreeJSDataSource ready for rendering

Supported Formats

Gaussian Splatting Formats

Format Extension Loader Class Description
Standard PLY .ply PLYLoader Standard 3DGS format (ASCII/Binary). Performs normalization and SH packing. Auto-detected by checking for 3DGS properties in header.
Compressed PLY .compressed.ply CompressedPLYLoader Quantized PLY format using chunk-based compression. Positions, rotations, scales, and colors are packed with quantization. Detected by .compressed.ply extension.
SPZ .spz SPZLoader GZIP-based container with quantized positions/rotations.
SOG .sog SOGLoader SuperOrdered Gaussians. Supports both Raw and ZIP-compressed variants. Detected by ZIP magic bytes (0x504b0304).
Splat .splat SplatLoader Raw binary dump format (32-byte stride). Extremely fast loading.
KSplat .ksplat KSplatLoader Luma AI optimized block format. Detected by "KSPL" magic bytes.

Mesh Formats (Three.js Adapters)

Format Extension Adapter Class Description
FBX .fbx FBXLoaderAdapter Wraps THREE.FBXLoader. Preserves materials and applies shadow settings.
GLTF/GLB .gltf, .glb GLTFLoaderAdapter Wraps THREE.GLTFLoader. Preserves materials and applies shadow settings.
OBJ .obj OBJLoaderAdapter Wraps THREE.OBJLoader. Supports MTL materials.
STL .stl STLLoaderAdapter Wraps THREE.STLLoader.
Mesh PLY .ply ThreeJSPLYLoaderAdapter For PLY files containing traditional triangle meshes (detected when 3DGS properties are absent).

Loader Types

UniversalLoader

The main loader that handles both Gaussian Splatting and Three.js mesh formats. It maintains two separate registries and intelligently routes files based on format detection.

Features: - Dual registry system (Gaussian and Three.js) - Automatic PLY disambiguation (3DGS vs mesh) - Magic byte detection for compressed formats - Runtime loader registration

UniversalGaussianLoader

A specialized loader that only handles Gaussian Splatting formats. Useful when you know you're only working with Gaussian data.

Features: - Single-purpose: Gaussian formats only - Simpler API surface - Faster format detection (no Three.js registry lookup)

Format Detection

The IO module provides several utilities for format detection:

import { 
  detectGaussianFormat, 
  isGaussianFormat, 
  GaussianFormat,
  isGaussianDataSource,
  isThreeJSDataSource 
} from 'src/io';

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

// Check if file is Gaussian format
if (isGaussianFormat('model.ply')) {
  // Handle Gaussian file
}

// Type guards for runtime type checking
if (isGaussianDataSource(data)) {
  const points = data.numPoints();
}

if (isThreeJSDataSource(data)) {
  const obj = data.object3D();
}

PLY Disambiguation

The module automatically detects whether a .ply file is a 3D Gaussian Splatting file or a traditional mesh file by checking the header for required 3DGS properties:

  • property float opacity
  • property float scale_0, scale_1, scale_2
  • property float rot_0, rot_1, rot_2, rot_3

If all these properties are present, the file is treated as a 3DGS file; otherwise, it's routed to the Three.js PLY loader.

Performance Characteristics

  • Loading Speed: Optimized for large datasets (>1M points)
  • Memory Usage: Efficient half-precision packing reduces GPU memory by 50%
  • Progress Granularity: Sub-second updates for responsive UI
  • Error Recovery: Graceful handling of malformed files
  • Streaming: Large files are processed incrementally to avoid blocking

Integration Points

The IO module integrates with:

  • App Module: Used by FileLoader manager for unified asset loading
  • Point Cloud Module: Provides data for GPU buffer creation
  • Renderer: Supplies preprocessed Gaussian parameters
  • Utils: Half-precision conversion and mathematical utilities
  • Architecture – Loader registry diagrams, buffer layout contracts, and preprocess handoff.
  • API Reference – Full list of loader classes, detection helpers, and progress callbacks.