How to Publish and Export Data from SuperSplat: A Complete Technical Guide

SuperSplat provides two distinct data workflows—publishing uploads PLY scenes to the PlayCanvas backend to create shareable .sog files, while exporting serializes splat data locally to PLY, compressed PLY, SOG, or bundled HTML viewer formats using the serialization functions in src/splat-serialize.ts.

SuperSplat, the open-source Gaussian Splat editor maintained by PlayCanvas, offers robust pipelines for both cloud publishing and local file export. Understanding how to publish and export data from SuperSplat requires familiarity with its event-driven architecture and the specific TypeScript modules that handle Gaussian splat transformations. This guide examines the actual implementation in the playcanvas/supersplat repository to show you exactly how these workflows operate under the hood.

Publishing Scenes to the PlayCanvas Cloud

The publishing workflow is triggered by the scene.publish event and implemented primarily in src/publish.ts. This process authenticates users, performs multipart uploads, and creates or updates splat records via the PlayCanvas API.

Authentication and User Credentials

Before uploading, the system retrieves user credentials by calling fetchUser(), which makes a request to <origin>/api/id to obtain a User object containing the user id, authentication token, and API server endpoint.

Multipart Upload Process

The actual file upload uses PublishWriter.create() to initiate a multipart upload on the PlayCanvas upload/start-upload endpoint. The implementation streams PLY data in 10 MiB chunks, tracking progress through the ProgressWriter wrapper, and finalizes with a call to upload/complete-upload.

Creating or Updating Splats Records

After successful upload, the system either creates a new splat record or updates an existing one:

  • New publication: doPublish() sends a POST request to ${apiServer}/splats/publish with the S3 key, title, description, visibility flag, and experience settings.
  • Republishing: If an overwriteId is provided, doRepublish() sends a PUT request to ${apiServer}/splats/${overwriteId}/republish to update the existing record.

The request body includes experience settings (camera configuration, animation data, and post-effects) alongside the file metadata.

Publishing Code Example

import { registerPublishEvents, PublishSettings } from './src/publish';

async function publishScene(settings: PublishSettings) {
    // Register handlers (typically done once on application startup)
    registerPublishEvents(events);
    
    // Trigger the publishing workflow
    await events.invoke('scene.publish', settings);
}

// Configure publishing parameters
const settings: PublishSettings = {
    user: await fetchUser(),
    title: 'My Gaussian Scene',
    description: 'Processed with SuperSplat',
    listed: true,
    serializeSettings: { maxSHBands: 3, selected: false },
    experienceSettings: { /* camera & post-effect configuration */ },
    overwriteId: 'abc123', // Optional: for updating existing scenes
};

publishScene(settings);

Exporting Scenes Locally

Exporting operates entirely client-side through the functions defined in src/splat-serialize.ts. This module leverages the @playcanvas/splat-transform library to convert in-memory Gaussian data into various binary formats.

Supported Export Formats

SuperSplat supports four primary export targets:

  • Standard PLY: serializePly outputs uncompressed binary PLY files
  • Compressed PLY: serializePlyCompressed packs data into 256-splat chunks for reduced file size
  • SOG format: serializeSog produces GPU-compressed binary optimized for PlayCanvas rendering
  • HTML Viewer: serializeViewer generates self-contained HTML files or ZIP bundles with embedded assets

The Serialization Pipeline

All export functions share a common architecture implemented in src/splat-serialize.ts:

  1. FileSystem setup: Creates either a WriterFileSystem for streamed downloads or MemoryFileSystem for in-memory ZIP generation
  2. Progress wrapping: Instantiates a ProgressWriter to emit progressUpdate events to the UI
  3. Data preparation: Initializes a SingleSplat reader to extract per-Gaussian values while applying world-space transforms, color tinting, and opacity conversion
  4. Filtering and writing: Uses GaussianFilter to iterate over valid gaussians, writing vertices to binary buffers and flushing when full
  5. Finalization: Closes the writer to release resources and trigger downloads

Exporting to PLY Format

import { serializePly, SerializeSettings } from './src/splat-serialize';
import { WriterFileSystem } from './src/publish';

async function exportToPly(splats, settings: SerializeSettings) {
    // Create a writer that streams to browser download
    const writer = await createDownloadWriter('scene.ply');
    const fs = new WriterFileSystem(writer);
    
    // Serialize with progress tracking
    await serializePly(splats, settings, fs, 'scene.ply');
    
    // Finalize and trigger download
    await writer.close();
}

Creating Bundled HTML Viewers

For sharing interactive scenes, serializeViewer generates standalone HTML files:

import { serializeViewer, ViewerExportSettings } from './src/splat-serialize';

async function exportViewer(splats, serializeSettings, experienceSettings) {
    const exportOpts: ViewerExportSettings = {
        type: 'html', // or 'zip' for packaged assets
        experienceSettings,
        events // Optional: for UI progress callbacks
    };
    
    const writer = await createDownloadWriter('viewer.html');
    const fs = new WriterFileSystem(writer);
    
    await serializeViewer(splats, serializeSettings, exportOpts, fs);
    await writer.close();
}

Note: The HTML export automatically initializes a WebGPU device via createGpuDevice() for GPU-accelerated SOG compression, falling back to CPU processing if WebGPU is unavailable.

Shared Infrastructure and Utilities

Both publishing and exporting rely on common abstractions defined in src/io/index.ts and the central event bus.

FileSystem Abstractions

The WriterFileSystem class provides a unified interface for file operations, whether streaming to network uploads (publishing) or local blobs (exporting). For ZIP archive creation, the system uses MemoryFileSystem to manage in-memory file structures before final compression.

Progress Tracking and UI Integration

The ProgressWriter wrapper (found in src/io/index.ts) monitors byte-level progress and fires progressStart, progressUpdate, and progressEnd events. These events drive the UI components in src/ui/popup.ts and src/ui/status-bar.ts, displaying upload progress bars and completion notifications.

Event Architecture

The entire workflow is orchestrated through the Events system (src/events.ts), which decouples the serialization logic from UI components. When publishing, the scene.publish event triggers the chain of authentication, upload, and API calls, while export operations use the same event bus for progress feedback without network dependencies.

Summary

  • Publishing requires authentication against the PlayCanvas API, streams PLY data via multipart upload in 10 MiB chunks, and creates or updates splat records at the /splats/publish or /splats/{id}/republish endpoints.
  • Exporting uses client-side serialization functions (serializePly, serializeViewer, etc.) in src/splat-serialize.ts to generate PLY, compressed PLY, SOG, or HTML outputs via the splat-transform library.
  • Both workflows utilize shared infrastructure including WriterFileSystem for I/O abstraction, ProgressWriter for feedback, and the central Events bus for UI coordination.
  • File locations: Core publishing logic resides in src/publish.ts, while export functionality is centralized in src/splat-serialize.ts, with I/O utilities in src/io/index.ts.

Frequently Asked Questions

What is the difference between publishing and exporting in SuperSplat?

Publishing uploads your scene to PlayCanvas servers, creating a shareable .sog file accessible via URL, while exporting generates local files (PLY, SOG, or HTML) that remain on your machine. Publishing requires an internet connection and PlayCanvas account authentication, whereas exporting works entirely offline using the serialization pipeline in src/splat-serialize.ts.

How do I update an existing published scene instead of creating a new one?

Provide the overwriteId parameter in your PublishSettings object when invoking the scene.publish event. When overwriteId is present, the system calls doRepublish() which sends a PUT request to ${apiServer}/splats/${overwriteId}/republish rather than creating a new record via POST.

What format should I use for the smallest file size?

Use compressed PLY via serializePlyCompressed for standard editing workflows, or SOG format via serializeSog for web deployment. The compressed PLY format packs gaussians into 256-splat chunks, while SOG applies additional GPU-friendly compression. For maximum compatibility, the compressed PLY offers the best balance between size and software support.

Can I export a scene without installing the full SuperSplat application?

Yes, by utilizing the HTML viewer export via serializeViewer. This generates a self-contained HTML file with embedded WebGPU rendering that opens directly in compatible browsers without requiring the SuperSplat editor. The export process handles all compression and asset bundling automatically, producing either a single .html file or a .zip package depending on the type parameter.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →