Bridge Protocol

Raw postMessage contract between Retor and the host. Use this if you're integrating from a framework the SDKs don't cover.

Envelope

Every message uses the same envelope:

{
  "source": "retor" | "retor-host",
  "type": "...",
  "payload": { ... }
}

source: "retor" — messages from Retor to the host.
source: "retor-host" — messages from the host to Retor.

Always check source before handling. Other apps on the page may also be using postMessage.

Outbound (Retor → host)

init

Fires once when the project data is loaded.

{
  "source": "retor",
  "type": "init",
  "payload": {
    "project": {
      "_id": "...",
      "name": "...",
      "description": "...",
      "startViewId": "..."
    },
    "lines": [
      {
        "_id": "...",
        "name": "...",
        "description": "...",
        "subtitle": "...",
        "autoplay": false,
        "autoplaySpeed": 1,
        "scrollType": "observe" | "track",
        "closed": false,
        "notesSupported": false,
        "tags": [
          {
            "_id": "...",
            "name": "...",
            "description": "...",
            "subtitle": "...",
            "index": 0,
            "position": { "x": 0, "y": 0, "z": 0 },
            "split": false,
            "color": "#...",
            "tagType": "bubble",
            "iconName": null
          }
        ]
      }
    ]
  }
}

line-open

A line's scroll path was entered.

{ "source": "retor", "type": "line-open", "payload": { "lineId": "..." } }

line-close

The user left the current line.

{ "source": "retor", "type": "line-close" }

line-progress

Fires continuously (RAF) while inside a line.

{
  "source": "retor",
  "type": "line-progress",
  "payload": {
    "progress": 0.423,
    "closestTagId": "..."
  }
}

Inbound (host → Retor)

open-line

Enter a line's scroll path.

{ "source": "retor-host", "type": "open-line", "payload": { "lineId": "..." } }

exit-line

Leave the current line.

{ "source": "retor-host", "type": "exit-line" }

scroll-to-tag

Jump the camera along the current line's path to a specific tag.

{ "source": "retor-host", "type": "scroll-to-tag", "payload": { "tagId": "..." } }

toggle-autoplay

Toggle the playing state.

{ "source": "retor-host", "type": "toggle-autoplay" }

set-autoplay

Explicitly set the playing state.

{ "source": "retor-host", "type": "set-autoplay", "payload": { "playing": true } }

set-notes

Push an array of user-generated notes (same shape as tags) into the scene. Retor merges them into the active line's tag list. Send again with an updated array to sync changes.

{
  "source": "retor-host",
  "type": "set-notes",
  "payload": {
    "notes": [
      {
        "_id": "note-1",
        "name": "Loose rock",
        "description": "Watch the flake",
        "position": { "x": 1.2, "y": 3.4, "z": 5.6 },
        "objectId": "line-abc"
      }
    ]
  }
}

Vanilla Mode

Append ?vanilla=true to the preview URL to hide Retor's built-in UI:

https://retor.app/p/abc123?vanilla=true

Only the 3D scene is rendered — the bridge still works for events and commands.

Raw iframe example

<iframe id="retor" src="https://retor.app/p/abc123?vanilla=true" style="width:100%;height:100%;border:0"></iframe>

<script>
  const iframe = document.getElementById("retor");

  // Receive
  window.addEventListener("message", (e) => {
    if (e.data?.source !== "retor") return;
    console.log(e.data.type, e.data.payload);
  });

  // Send — wait for load before posting
  iframe.addEventListener("load", () => {
    iframe.contentWindow.postMessage(
      { source: "retor-host", type: "open-line", payload: { lineId: "..." } },
      "*"
    );
  });
</script>