Plugins in Visualizer do not run as a single piece of code. Instead, each Plugin is split into two parts that run in separate environments and communicate with each other. This architecture determines what your code can and cannot do depending on where it runs.
How Plugins run
Section titled “How Plugins run”When a Plugin loads, Visualizer runs its code in two environments:
- A WebAssembly environment, which has direct access to Visualizer data and the Plugin API.
- An iframe environment, which handles all UI rendering and has access to standard browser APIs.
Neither environment can do everything on its own. WebAssembly can read and interact with Visualizer data but cannot render HTML or call most browser APIs. The iframe can render HTML and call browser APIs but cannot access Visualizer data directly. Together, they complement each other.
The two sides communicate using postMessage, a standard browser mechanism
for safe communication between separate execution contexts. When the UI needs
data from Visualizer, it requests the data from the WebAssembly side, which
fetches it and sends it across.
WebAssembly side
Section titled “WebAssembly side”The WebAssembly side is the Plugin’s entry point. This is the first code that runs when a Plugin loads, and it runs synchronously in the same thread as Visualizer.
What you can do:
- Access scene data from Visualizer.
- Call the Plugin API.
- Partially update the Visualizer scene, such as changing layer properties.
- Subscribe to events from the scene.
- Send data to and receive data from the iframe side via
postMessage.
What you cannot do:
- Render HTML or any UI directly; this must be handled on the iframe side.
- Use most browser APIs; a limited set is available, such as
console.log. - Make HTTP requests to external servers.
The iframe side
Section titled “The iframe side”The iframe side handles everything visual in your Plugin. It behaves like a standard web page and has access to browser APIs.
What you can do:
- Render HTML as you would in a normal web page.
- Use browser APIs, including DOM APIs, Canvas, and
fetch. - Make HTTP requests to external servers when the server includes
Access-Control-Allow-Origin: *in its response headers. - Send data to and receive data from the WebAssembly side via
postMessage.
What you cannot do:
- Access or change Visualizer data directly; request it from the WebAssembly
side via
postMessage. - Communicate with the Visualizer back end directly.
- Make HTTP requests to servers that do not include
Access-Control-Allow-Origin: *in their response headers because the iframe is sandboxed with a null origin. - Use local storage for the same sandboxing reason.
- Use browser APIs that require explicit permission from the parent page. For example, the Clipboard API is not available by default in the sandboxed iframe.
Key takeaways
Section titled “Key takeaways”| Capability | WebAssembly side | iframe side |
|---|---|---|
| Sandboxed | ✅ | ✅ |
| Entry point (runs first) | ✅ | ❌ |
| Access to Plugin API | ✅ | ❌ |
| Render HTML | ❌ | ✅ |
| Use browser APIs | ❌ | ✅ |
Communicate via postMessage | ✅ | ✅ |
Limitations
Section titled “Limitations”postMessage serialization: postMessage can only send data that can be
serialized as JSON. Objects such as ArrayBuffer and Blob cannot be sent
directly. Encode binary data as a base64 string before transferring it.
Plugin size: Plugins must be packaged as .zip files of 10 MB or less.
Static assets: Non-JavaScript files such as images, HTML, and CSS cannot be packaged inside a Plugin. Embed them in JavaScript as strings, or host them on a publicly accessible server and reference them by URL.
Local storage: Local storage is unavailable on both sides. To persist data, use the storage API provided by the Plugin API or an external server.