How to Use the SuperSplat Iframe API for External Integration

The SuperSplat iframe API enables external web applications to communicate with the embedded editor via window.postMessage, allowing parent windows to query internal scene state such as unsaved changes and receive typed responses.

SuperSplat, the open-source Gaussian Splat editor maintained by PlayCanvas, exposes a lightweight message-based API for secure cross-origin integration. Located in the playcanvas/supersplat repository, this API—implemented primarily in src/iframe-api.ts—allows developers to embed the 3D editor within host applications and programmatically inspect editor state without direct DOM manipulation.

Understanding the SuperSplat Iframe API Architecture

The API implementation attaches a message event listener to the iframe's window object inside src/iframe-api.ts. When a parent window posts a message matching a supported query shape, SuperSplat validates the payload using TypeScript type guards and invokes internal functions through the shared Events object defined in src/events.ts.

The communication follows a strict request-response pattern:

  1. The parent page sends a JSON message via postMessage containing { type: "supersplat:is-scene-dirty" }
  2. SuperSplat receives the message, validates it using the isSceneDirtyQuery guard, and calls events.invoke('scene.dirty') to check the internal state
  3. SuperSplat replies with { type: "supersplat:is-scene-dirty", result: <boolean> } posted back to the originating window's origin

Because the system relies on standard window.postMessage, it works securely across different origins while keeping the editor's internal implementation encapsulated.

Querying Scene State from the Parent Window

The current API implementation supports checking whether the active scene contains unsaved modifications. This is essential for host applications that need to display save prompts or prevent accidental data loss before closing the editor.

Checking for Unsaved Changes

The isSceneDirtyQuery function in src/iframe-api.ts validates incoming messages before processing. When invoked, it returns true if pending changes exist in the scene, or false if the state is saved.

<!-- parent.html -->
<iframe id="splatIframe" src="https://your.domain/supersplat.html"></iframe>

<script>
const iframe = document.getElementById('splatIframe');

// Ask SuperSplat whether the scene is dirty
function askIfSceneDirty() {
    const msg = { type: 'supersplat:is-scene-dirty' };
    iframe.contentWindow.postMessage(msg, '*');
}

// Listen for SuperSplat's response
window.addEventListener('message', (e) => {
    const data = e.data;
    if (data && data.type === 'supersplat:is-scene-dirty') {
        console.log('Scene dirty?', data.result); // true | false
    }
});

// Example usage
askIfSceneDirty();
</script>

The handler specifically checks event.data.type to filter SuperSplat messages from other postMessage traffic, ensuring your application only processes relevant responses.

Integrating SuperSplat into React Applications

For React-based host applications, you can wrap the iframe communication in a functional component using useRef and useEffect hooks. This pattern maintains type safety and ensures proper cleanup of global event listeners when the component unmounts.

import React, { useEffect, useRef } from 'react';

const SuperSplatHost = () => {
  const iframeRef = useRef<HTMLIFrameElement>(null);

  // Ask the iframe if the scene is dirty
  const checkDirty = () => {
    iframeRef.current?.contentWindow?.postMessage(
      { type: 'supersplat:is-scene-dirty' },
      '*'
    );
  };

  // Handle the reply
  useEffect(() => {
    const handler = (e: MessageEvent) => {
      const d = e.data;
      if (d?.type === 'supersplat:is-scene-dirty') {
        alert(`Scene dirty: ${d.result}`);
      }
    };
    window.addEventListener('message', handler);
    return () => window.removeEventListener('message', handler);
  }, []);

  return (
    <>
      <button onClick={checkDirty}>Is Scene Dirty?</button>
      <iframe
        ref={iframeRef}
        src="https://your.domain/supersplat.html"
        style={{ width: '100%', height: '80vh', border: 'none' }}
      />
    </>
  );
};

export default SuperSplatHost;

Extending the Iframe API with Custom Queries

While the current implementation only exposes the scene dirty check, the modular architecture in src/iframe-api.ts supports straightforward extension. Developers can add new query types by defining TypeScript interfaces, adding validation guards, and wiring handlers to invoke methods on the Events object.

To add a camera state query, modify src/iframe-api.ts:

// In src/iframe-api.ts – add a new query type
const GET_CAMERA_STATE = 'supersplat:get-camera-state';

interface GetCameraStateQuery {
  type: typeof GET_CAMERA_STATE;
}

interface GetCameraStateResponse {
  type: typeof GET_CAMERA_STATE;
  result: { position: number[]; rotation: number[] };
}

const getCameraStateQuery = (data: any): data is GetCameraStateQuery =>
  data && typeof data === 'object' && data.type === GET_CAMERA_STATE;

// Inside the message listener …
if (getCameraStateQuery(event.data)) {
  const cam = events.invoke('camera.getState') as any;
  const response: GetCameraStateResponse = {
    type: GET_CAMERA_STATE,
    result: cam,
  };
  source.postMessage(response, event.origin);
}

After rebuilding the application, parent windows can request camera data by posting { type: 'supersplat:get-camera-state' } and receiving the position and rotation arrays in the response. This pattern can be replicated for any internal state accessible through the Events system defined in src/events.ts.

Summary

  • The SuperSplat iframe API in src/iframe-api.ts provides secure, cross-origin communication via postMessage
  • Query the scene dirty state by sending { type: 'supersplat:is-scene-dirty' } to the iframe content window
  • Responses return through the parent window's message event listener with matching type identifiers and boolean results
  • The API leverages the Events object from src/events.ts to safely invoke internal editor functions without exposing the full application state
  • Developers can extend the system by adding new query validators and response handlers following the established pattern in src/iframe-api.ts

Frequently Asked Questions

Does the SuperSplat iframe API support cross-origin communication?

Yes, the API is intentionally built on window.postMessage, which inherently supports secure cross-origin communication. As implemented in src/iframe-api.ts, SuperSplat validates incoming message shapes using TypeScript type guards like isSceneDirtyQuery before processing requests, ensuring that only properly formatted messages from any origin can query the editor's internal state.

What message types does the SuperSplat iframe API currently support?

As of the latest source code in the playcanvas/supersplat repository, the only built-in query type is supersplat:is-scene-dirty. This specific message returns a boolean indicating whether the current scene has unsaved changes. However, the architecture explicitly supports extension, allowing developers to add new query types by defining additional interfaces and validation functions in src/iframe-api.ts.

How does SuperSplat validate incoming API messages?

SuperSplat validates messages using TypeScript type guard functions defined in src/iframe-api.ts. For example, the isSceneDirtyQuery function strictly checks that the incoming data is an object containing type: 'supersplat:is-scene-dirty'. After validation succeeds, the handler calls events.invoke('scene.dirty') through the event system defined in src/events.ts to retrieve the internal state before posting the result back to the parent window.

Can I trigger actions in SuperSplat from the parent window, or only query state?

The current implementation in src/iframe-api.ts focuses on querying read-only state rather than triggering mutations. The existing pattern uses events.invoke() to safely read values like the dirty status without modifying the scene. To trigger actions such as saving or transforming objects, you would need to extend the API by adding new message handlers that invoke appropriate mutating methods on the Events object, following the same validation and origin-checking patterns established for the scene dirty query.

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 →