# SuperSplat File Handling and Drag-and-Drop: How the Import Pipeline Works

> Discover how SuperSplat's unified import pipeline handles file imports and drag-and-drop. Learn about the virtual file system for Gaussian splat models.

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

---

**SuperSplat centralizes all file import operations in [`src/file-handler.ts`](https://github.com/playcanvas/supersplat/blob/main/src/file-handler.ts), supporting native file pickers, fallback HTML inputs, and drag-and-drop through a unified `importFiles` pipeline that converts dropped items into a virtual file system before loading Gaussian splat models.**

SuperSplat, the open-source 3D Gaussian Splatting editor from the PlayCanvas team (`playcanvas/supersplat`), provides multiple entry points for bringing assets into the scene. Whether users select files through the operating system dialog, drop them onto the canvas, or load entire animation sequences, all paths converge in a single orchestration layer that handles format detection, virtual file system creation, and scene integration.

## The Central File Handler Architecture

The entry point for all file operations is the `initFileHandler` function exported from [`src/file-handler.ts`](https://github.com/playcanvas/supersplat/blob/main/src/file-handler.ts). When the editor initializes (typically in [`src/editor.ts`](https://github.com/playcanvas/supersplat/blob/main/src/editor.ts)), the system invokes `initFileHandler(scene, events, dropTarget)` to wire up the three input mechanisms and register the public API functions `scene.import`, `scene.openAnimation`, `scene.export`, and `scene.write`.

At lines 62-64 of [`file-handler.ts`](https://github.com/playcanvas/supersplat/blob/main/file-handler.ts), the handler registers itself with the events system:

```typescript
events.function('import', async () => {
    return importFiles(await showOpenFilePicker(), false);
});

```

This registration allows UI components like the toolbar to trigger imports via `events.invoke('scene.import')`.

## Three Import Pathways

SuperSplat supports three distinct input methods to maximize browser compatibility and user convenience. Each method ultimately constructs an `ImportFile[]` array—containing filename, `File` object, and optional file-system handle—and passes it to the core `importFiles` function.

### Native File Picker

Modern browsers supporting the File System Access API use `window.showOpenFilePicker` (lines 52-58). This opens the OS native file picker, reads selected file handles, and maps them directly to the `ImportFile` structure without creating temporary copies.

### Fallback HTML Input

For browsers lacking the File System Access API, the system creates a hidden `<input type="file">` element (lines 66-88). Configured to accept all supported extensions (`.ply`, `.splat`, `.sog`, `.json`, etc.), this input's `onchange` handler builds the same `ImportFile[]` structure, ensuring consistent behavior across legacy environments.

### Drag-and-Drop Handler

The third path uses `CreateDropHandler` imported from [`src/drop-handler.ts`](https://github.com/playcanvas/supersplat/blob/main/src/drop-handler.ts). Attached to the supplied `dropTarget` element (usually the main canvas), this handler captures `dragenter`, `dragover`, `dragleave`, and `drop` events. When files are dropped, the handler extracts file-system entries and converts them into `ImportFile` objects (lines 90-99):

```typescript
CreateDropHandler(dropTarget, (entries, shift) => {
    const files = entries.map(e => ({
        filename: e.filename,
        contents: e.file,
        handle: e.handle
    }));
    importFiles(files);
});

```

## The Import Pipeline

Once `importFiles` receives the file array, it executes a four-stage pipeline to prepare assets for the WebGL scene.

### Format Detection

Before loading, helper functions `isPlySequence`, `isSog`, and `isLcc` (lines 13-45) examine lower-cased filenames to categorize the payload. The system distinguishes between:
- PLY animation sequences (multiple sequential `.ply` files)
- SOG scene bundles
- LCC asset bundles
- Individual model or project files

### Virtual File System Creation

To resolve relative asset paths without copying files to disk, the system instantiates `MappedReadFileSystem` from [`src/io/browser-file-system.ts`](https://github.com/playcanvas/supersplat/blob/main/src/io/browser-file-system.ts) (line 85). If the main file originated from a remote URL, this virtual file system uses the base URL to resolve dependencies. All supplied `File` objects are added via `fileSystem.addFile`, creating a read-only sandbox for the loader.

### Model Loading and Scene Integration

The actual asset loading occurs at line 95:

```typescript
const model = await scene.assetLoader.load(filename, fileSystem, animationFrame);
scene.add(model);

```

The `assetLoader` reads the primary file (PLY, SPLAT, SOG, etc.) using the virtual file system, parses the Gaussian-splat data into a `Splat` instance, and inserts it into the active `Scene` managed by [`src/scene.ts`](https://github.com/playcanvas/supersplat/blob/main/src/scene.ts) and [`src/scene-state.ts`](https://github.com/playcanvas/supersplat/blob/main/src/scene-state.ts).

## Special Format Handling

### PLY Sequences

When the detector identifies a PLY sequence, the handler fires two UI events (lines 110-113):

```typescript
events.fire('plysequence.setFrames', files.map(f => f.contents));
events.fire('timeline.frame', 0);

```

This populates the timeline with animation frames and jumps to the first frame.

### SOG and LCC Bundles

For SOG and LCC formats, the system prompts for user confirmation (lines 115-124) before proceeding through the same `importSplatModel` path. This prevents accidental overwrites of complex scene state.

### Individual File Routing

For non-sequence imports, the loop starting at line 138 iterates over each entry and routes files to specialized loaders based on extension:
- `.ssproj` (project files)
- `.ply`, `.splat` (Gaussian splats)
- `.sog` (scene bundles)
- [`images.txt`](https://github.com/playcanvas/supersplat/blob/main/images.txt), `.json` (configuration data)

## Drag-and-Drop Implementation Details

The `CreateDropHandler` in [`src/drop-handler.ts`](https://github.com/playcanvas/supersplat/blob/main/src/drop-handler.ts) serves as a thin DOM abstraction layer. It transforms the native HTML5 drag-and-drop API into a callback-based interface that yields file-system entries. This design keeps browser-specific event handling separate from the import logic, ensuring that [`file-handler.ts`](https://github.com/playcanvas/supersplat/blob/main/file-handler.ts) treats dropped files identically to those selected via the file picker.

The handler manages CSS drag states and extracts `FileSystemEntry` objects from the `DataTransferItemList`, converting them to the standard `ImportFile` shape before invoking the callback passed from `initFileHandler`.

## Summary

- **Centralized import logic** lives in [`src/file-handler.ts`](https://github.com/playcanvas/supersplat/blob/main/src/file-handler.ts), specifically the `initFileHandler` and `importFiles` functions.
- **Three entry points**—native file picker (lines 52-58), fallback HTML input (lines 66-88), and drag-and-drop (lines 90-99)—all converge on the same `ImportFile[]` structure.
- **Format detection** uses `isPlySequence`, `isSog`, and `isLcc` (lines 13-45) to determine loading strategy.
- **Virtual file system** (`MappedReadFileSystem` at line 85) enables the loader to resolve relative paths in drag-and-drop scenarios.
- **Drag-and-drop** relies on `CreateDropHandler` from [`src/drop-handler.ts`](https://github.com/playcanvas/supersplat/blob/main/src/drop-handler.ts) to normalize DOM events into file entries.
- **Scene integration** occurs via `scene.assetLoader.load` followed by `scene.add`, with special event firing for PLY sequences (`plysequence.setFrames`).

## Frequently Asked Questions

### How does SuperSplat handle file imports in browsers without the File System Access API?

SuperSplat creates a hidden `<input type="file">` element configured with all supported extensions. When triggered, this fallback input's `onchange` handler constructs the same `ImportFile[]` array used by the native picker, ensuring consistent behavior across legacy browsers like Safari or older Firefox versions.

### What happens when I drag and drop a folder containing PLY files?

The `CreateDropHandler` extracts all file entries from the dropped folder and passes them to `importFiles`. If the filenames match a sequential pattern, `isPlySequence` identifies them as an animation sequence, firing `plysequence.setFrames` to load them into the timeline and automatically setting the current frame to zero.

### Where does SuperSplat store files during the import process?

SuperSplat does not copy files to persistent storage. Instead, it creates a `MappedReadFileSystem` instance in memory (implemented in [`src/io/browser-file-system.ts`](https://github.com/playcanvas/supersplat/blob/main/src/io/browser-file-system.ts)) that maps the original `File` objects into a virtual directory structure. This allows the asset loader to resolve relative paths (like textures referenced by JSON) while keeping the data in browser memory.

### Can I programmatically trigger a file import without user interaction?

Yes. The `initFileHandler` registers an event function at lines 62-64 that exposes `events.invoke('scene.import')`. Your code can call this method to trigger the file picker programmatically, or you can directly call `importFiles` with a pre-constructed array of `ImportFile` objects if you already have access to the file data.