# How to Use the Native Embedder API (TrEmbedder) in JSAR

> Learn how to use the native embedder API TrEmbedder in JSAR. Subclass TrEmbedder, implement onEvent, configure runtime, and manage lifecycle hooks for seamless integration.

- Repository: [M Creative Lab/jsar-runtime](https://github.com/m-creativelab/jsar-runtime)
- Tags: how-to-guide
- Published: 2026-03-06

---

**To use the native embedder API in JSAR, subclass the abstract `TrEmbedder` class from [`src/runtime/embedder.hpp`](https://github.com/m-creativelab/jsar-runtime/blob/main/src/runtime/embedder.hpp), implement the pure virtual `onEvent` method, configure the runtime via `configure()`, and drive the rendering loop through the four lifecycle hooks: `onBeforeRendering()`, `onOpaquesRenderPass()`, `onTransparentsRenderPass()`, and `onAfterRendering()`.**

The **native embedder API** allows C++ applications to host the JSAR runtime within game engines like Unity, Unreal, or custom OpenGL/DirectX applications. Found in the `m-creativelab/jsar-runtime` repository, the `TrEmbedder` class serves as the bridge between your host engine and the JSAR content system, managing initialization, per-frame rendering, and native event handling.

## Architecture of the Native Embedder API

The native embedder API centers on the **`TrEmbedder`** abstract class defined in [`src/runtime/embedder.hpp`](https://github.com/m-creativelab/jsar-runtime/blob/main/src/runtime/embedder.hpp). This base class owns a **`TrConstellation`** instance—the central orchestrator declared in [`src/runtime/constellation.hpp`](https://github.com/m-creativelab/jsar-runtime/blob/main/src/runtime/constellation.hpp) that manages the renderer, content manager, and XR device.

Key architectural components include:

- **`TrEmbedder`**: The base class that host applications must inherit from. It encapsulates the `TrConstellation` runtime core and provides configuration, lifecycle management, and event handling APIs.
- **Lifecycle Hooks**: Virtual methods defined in [`src/runtime/embedder.cpp`](https://github.com/m-creativelab/jsar-runtime/blob/main/src/runtime/embedder.cpp) that the host calls each frame to execute rendering passes and advance the simulation.
- **Event System**: The pure virtual **`onEvent`** method that implementations must override to process native events such as RPC requests from JavaScript.
- **XR Integration**: Optional configuration via **`configureXrDevice`** to enable stereo rendering for AR/VR headsets.

## Creating a Custom Embedder Subclass

To integrate JSAR into your application, create a concrete subclass of `TrEmbedder` and implement the required virtual methods.

### Constructor and Renderer Setup

Inside your subclass constructor, specify the host engine type and initialize the Rendering Hardware Interface (RHI). The `TrEmbedder` constructor automatically instantiates the `constellation` member, allowing immediate access to `constellation->renderer` to set up your graphics backend.

```cpp
#include <runtime/embedder.hpp>
#include <renderer/render_api.hpp>

class MyEmbedder : public TrEmbedder {
public:
    MyEmbedder() : TrEmbedder(TrHostEngine::None) {
        auto renderer = constellation->renderer;
        auto rhi = RHIFactory::CreateRHI(kUnityGfxRendererOpenGLCore, constellation.get());
        renderer->setRHI(rhi);
    }
    
    // onEvent implementation required
};

```

### Implementing Event Handling

You must implement the pure virtual **`onEvent`** method to handle incoming native events. This method receives an `events_comm::TrNativeEvent` reference and a `std::shared_ptr<TrContentRuntime>` for sending responses.

```cpp
bool onEvent(events_comm::TrNativeEvent &event,
             std::shared_ptr<TrContentRuntime> content) override {
    if (event.type == events_comm::TrNativeEventType::RpcRequest) {
        auto request = event.detail<events_comm::TrRpcRequest>();
        if (request.method == "ping") {
            events_comm::TrRpcResponse resp(true);
            resp.message = "pong";
            content->respondRpcRequest(resp, event.id);
            return true;
        }
    }
    return false;
}

```

## Runtime Lifecycle Management

The embedder follows a strict initialization-to-shutdown lifecycle controlled by the host application.

### Configuration and Startup

Call **`configure(storageDir, proxy, enableXR)`** with a cache directory path, optional network proxy, and boolean XR flag, followed by **`start()`** to initialize the runtime:

```cpp
MyEmbedder embedder;
if (!embedder.configure("./jsar_cache", "", false)) {
    std::cerr << "Configuration failed\n";
    return -1;
}
if (!embedder.start()) {
    std::cerr << "Startup failed\n";
    return -1;
}

```

### Per-Frame Rendering Hooks

Drive the rendering loop by calling these methods in sequence every frame. These methods are implemented in [`src/runtime/embedder.cpp`](https://github.com/m-creativelab/jsar-runtime/blob/main/src/runtime/embedder.cpp) and forward calls to the internal `TrConstellation`:

1. **`onBeforeRendering()`** – Prepares the frame and updates the scene.
2. **`onOpaquesRenderPass()`** – Renders opaque geometry.
3. **`onTransparentsRenderPass()`** – Renders transparent geometry.
4. **`onAfterRendering()`** – Finalizes the frame and submits command buffers.

```cpp
for (int frame = 0; frame < 600; ++frame) {
    embedder.onBeforeRendering();
    embedder.onOpaquesRenderPass();
    embedder.onTransparentsRenderPass();
    embedder.onAfterRendering();
    
    std::this_thread::sleep_for(std::chrono::milliseconds(16));
}

```

When the host application exits, call **`shutdown()`** to clean up all internal services and release resources.

## Enabling XR Stereo Rendering

For XR applications, enable stereo rendering during configuration and provide device parameters:

```cpp
// Enable XR in configure
embedder.configure("./jsar_cache", "", true);

// Configure XR device properties
xr::TrDeviceInit xrInit;
xrInit.active = true;
xrInit.stereoRenderingMode = xr::StereoRenderingMode::SinglePass;
embedder.configureXrDevice(xrInit);

```

You can monitor runtime performance via **`getFps()`** and **`getUptime()`**, or retrieve version information using **`getVersion()`** during the frame loop.

## Complete Implementation Example

The file [`src/examples/desktop_opengl.cpp`](https://github.com/m-creativelab/jsar-runtime/blob/main/src/examples/desktop_opengl.cpp) provides a reference implementation named `DesktopEmbedder`. Below is a minimal standalone example combining all required components:

```cpp
#include <runtime/embedder.hpp>
#include <renderer/render_api.hpp>
#include <iostream>
#include <thread>
#include <chrono>

class MinimalEmbedder : public TrEmbedder {
public:
    MinimalEmbedder() : TrEmbedder(TrHostEngine::None) {
        auto rhi = RHIFactory::CreateRHI(kUnityGfxRendererOpenGLCore, constellation.get());
        constellation->renderer->setRHI(rhi);
    }

    bool onEvent(events_comm::TrNativeEvent &event,
                 std::shared_ptr<TrContentRuntime> content) override {
        return false;
    }
};

int main() {
    MinimalEmbedder embedder;
    
    if (!embedder.configure("./jsar_cache", "", false)) {
        return -1;
    }
    
    if (!embedder.start()) {
        return -1;
    }
    
    for (int i = 0; i < 600; ++i) {
        embedder.onBeforeRendering();
        embedder.onOpaquesRenderPass();
        embedder.onTransparentsRenderPass();
        embedder.onAfterRendering();
        std::this_thread::sleep_for(std::chrono::milliseconds(16));
    }
    
    embedder.shutdown();
    return 0;
}

```

## Summary

- **Subclass `TrEmbedder`** from [`src/runtime/embedder.hpp`](https://github.com/m-creativelab/jsar-runtime/blob/main/src/runtime/embedder.hpp) to create a host-specific implementation.
- **Implement `onEvent`** to handle RPC requests and native input events from the JavaScript runtime.
- **Call `configure()` and `start()`** to initialize; call `shutdown()` to destroy the runtime cleanly.
- **Drive rendering** via the four lifecycle hooks: `onBeforeRendering`, `onOpaquesRenderPass`, `onTransparentsRenderPass`, and `onAfterRendering`.
- **Access telemetry** through `getFps()` and `getUptime()` for performance monitoring.
- **Enable XR** by passing `true` to `configure()` and providing a filled `xr::TrDeviceInit` structure to `configureXrDevice()`.

## Frequently Asked Questions

### What is TrEmbedder in JSAR?

`TrEmbedder` is the abstract C++ base class defined in [`src/runtime/embedder.hpp`](https://github.com/m-creativelab/jsar-runtime/blob/main/src/runtime/embedder.hpp) that provides the interface between host applications and the JSAR runtime. It owns the `TrConstellation` core and declares pure virtual methods, including `onEvent`, that concrete implementations must provide to handle communication between the host engine and JavaScript content.

### How do I handle RPC requests in TrEmbedder?

Override the `onEvent` method to intercept events of type `events_comm::TrNativeEventType::RpcRequest`. Use `event.detail<events_comm::TrRpcRequest>()` to deserialize the request payload, then call `content->respondRpcRequest(response, event.id)` to send data back to the JavaScript context, as shown in [`src/examples/desktop_opengl.cpp`](https://github.com/m-creativelab/jsar-runtime/blob/main/src/examples/desktop_opengl.cpp).

### Can I use TrEmbedder without XR support?

Yes. Pass `false` as the third parameter to `configure(const std::string& storageDir, const std::string& proxy, bool enableXR)`. The runtime operates in standard mono rendering mode unless you explicitly enable XR and call `configureXrDevice()` with a valid `xr::TrDeviceInit` configuration.

### What rendering backends are supported by TrEmbedder?

The embedder supports multiple rendering backends through the RHI abstraction layer. You can initialize OpenGL, Vulkan, or engine-specific backends (Unity, Unreal, Cocos) by passing the appropriate renderer type constant to `RHIFactory::CreateRHI()`, then calling `constellation->renderer->setRHI()` with the resulting interface.