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

> Learn how to publish and export data from SuperSplat with this technical guide. Explore options for sharing PLY scenes or serializing splat data locally in various formats.

- Repository: [PlayCanvas/supersplat](https://github.com/playcanvas/supersplat)
- Tags: how-to-guide
- Published: 2026-05-10

---

**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`](https://github.com/playcanvas/supersplat/blob/main/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`](https://github.com/playcanvas/supersplat/blob/main/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

```typescript
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`](https://github.com/playcanvas/supersplat/blob/main/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`](https://github.com/playcanvas/supersplat/blob/main/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

```typescript
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:

```typescript
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`](https://github.com/playcanvas/supersplat/blob/main/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`](https://github.com/playcanvas/supersplat/blob/main/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`](https://github.com/playcanvas/supersplat/blob/main/src/ui/popup.ts) and [`src/ui/status-bar.ts`](https://github.com/playcanvas/supersplat/blob/main/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`](https://github.com/playcanvas/supersplat/blob/main/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`](https://github.com/playcanvas/supersplat/blob/main/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`](https://github.com/playcanvas/supersplat/blob/main/src/publish.ts), while export functionality is centralized in [`src/splat-serialize.ts`](https://github.com/playcanvas/supersplat/blob/main/src/splat-serialize.ts), with I/O utilities in [`src/io/index.ts`](https://github.com/playcanvas/supersplat/blob/main/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`](https://github.com/playcanvas/supersplat/blob/main/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.