# How JSAR Enables Immersive Web Content Creation: Architecture and Implementation Guide

> Discover how JSAR enables immersive web content creation by merging browser engines with XR pipelines. Learn about architecture and implementation with the TrEmbedder API.

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

---

**JSAR enables immersive web content creation by integrating a full-featured browser engine with native XR pipelines, allowing HTML/CSS/JavaScript content to be spatially positioned and rendered as 3D objects within VR/AR environments through the `TrEmbedder` API and WebXR session management.**

JSAR (JavaScript-AR) is a specialized browser runtime built specifically for the Spatial Web, bridging standard web technologies with immersive 3D engines. This article examines how the `m-creativelab/jsar-runtime` repository implements immersive web content creation through its embedder architecture, XR device management, and spatial rendering pipeline.

## Architectural Foundation for Immersive Web Content

JSAR operates through a layered architecture that transforms ordinary web pages into first-class 3D objects. The system combines an embedded V8 JavaScript engine with native XR device management to render spatialized DOM elements inside host engines like Unity or Unreal.

### The Embedder API Interface

At the C++ level, JSAR exposes the `TrEmbedder` virtual class defined in [`docs/api/embedder.md`](https://github.com/m-creativelab/jsar-runtime/blob/main/docs/api/embedder.md). This interface allows host engines to initialize, control, and shut down the runtime through standardized lifecycle hooks. Embedder implementations override methods including `onStart`, `onBeforeRendering`, and `onOpaquesRenderPass` to drive the rendering loop and manage resource allocation.

### XR Device and Session Management

The XR subsystem centers on two primary components. The `Device` class in [`src/xr/device.hpp`](https://github.com/m-creativelab/jsar-runtime/blob/main/src/xr/device.hpp) manages WebXR sessions, input sources, and stereo rendering configurations. When a session initiates, the runtime creates a `TrXRSession` object implemented in [`src/xr/session.cpp`](https://github.com/m-creativelab/jsar-runtime/blob/main/src/xr/session.cpp), which tracks per-eye view matrices, projection data, and frustum culling for spatial rendering.

### Content Runtime and Spatial Rendering

Standard web content loads through the runtime layer ([`runtime/content.hpp`](https://github.com/m-creativelab/jsar-runtime/blob/main/runtime/content.hpp)) and renders via the content renderer ([`renderer/content_renderer.hpp`](https://github.com/m-creativelab/jsar-runtime/blob/main/renderer/content_renderer.hpp)). The engine treats the DOM as a scene graph where every HTML element receives 3D coordinates. To maintain performance on mobile XR hardware, the renderer batches all spatialized DOM elements into **≤10 GPU draw calls per frame**, minimizing overhead while preserving visual fidelity.

## How JSAR Achieves Spatial Immersion

JSAR creates immersive experiences through five core technical mechanisms that bridge web standards with native 3D pipelines:

1. **Spatialized DOM Processing** – The renderer assigns 3D coordinates to every HTML element and applies the session’s `baseMatrix` to position the entire web page in world space, effectively converting CSS layouts into spatial scene graphs.

2. **WebXR Integration** – The `Device` class exposes the complete WebXR API, creating `TrXRSession` objects that drive per-eye view and projection matrices for stereoscopic rendering.

3. **Stereo Rendering Modes** – JSAR supports **Multi-Pass**, **Single-Pass**, **Instanced**, and **Multiview** pipelines. Host engines select the optimal mode for their graphics API (OpenGL, Metal, or D3D11) through the `StereoRenderingMode` enumeration.

4. **Low Draw-Call Overhead** – By batching DOM elements into a minimal set of GPU draw calls (≤10 per frame), JSAR maintains high frame rates critical for comfortable VR/AR experiences on resource-constrained hardware.

5. **Cross-Platform Host Integration** – Through inheritance from `TrEmbedder`, any 3D engine can embed JSAR, start the runtime with JSON configuration, and synchronize rendering via per-frame hooks like `onBeforeRendering`.

## Implementation Examples

### Creating a Custom C++ Embedder

Host engines integrate JSAR by implementing the `TrEmbedder` interface. The following example demonstrates a Unity-compatible embedder that configures XR for single-pass multiview rendering:

```cpp
#include "embedder/TrEmbedder.h"
#include "xr/device.hpp"

class MyUnityEmbedder : public TrEmbedder {
public:
  MyUnityEmbedder() : TrEmbedder(TrHostEngine::Unity) {}

  void onStart(std::string argJson) override {
    xr::TrDeviceInit xrInit;
    xrInit.active = true;
    xrInit.stereoRenderingMode = xr::StereoRenderingMode::SinglePassMultiview;
    configureXrDevice(true, xrInit);
  }

  void onBeforeRendering() override {
    if (!contentLoaded) {
      loadUrl("https://example.com/immersive.html");
      contentLoaded = true;
    }
  }
};

```

*Key references*: `TrEmbedder` definition in [`docs/api/embedder.md`](https://github.com/m-creativelab/jsar-runtime/blob/main/docs/api/embedder.md); XR configuration in [`src/xr/device.hpp`](https://github.com/m-creativelab/jsar-runtime/blob/main/src/xr/device.hpp).

### Requesting XR Sessions from JavaScript

Web developers request immersive sessions using standard WebXR APIs. The JSAR runtime intercepts these calls through the native bridge:

```javascript
if (navigator.xr) {
  navigator.xr.requestSession('immersive-vr', { 
    requiredFeatures: ['local-floor'] 
  })
  .then(session => {
    console.log('JSAR XR session started', session);
  })
  .catch(err => console.error('Failed to start XR session', err));
}

```

The native side receives the request via `Device::requestSession` (declared in [`src/xr/device.hpp`](https://github.com/m-creativelab/jsar-runtime/blob/main/src/xr/device.hpp)) and instantiates a `TrXRSession` object (implemented in [`src/xr/session.cpp`](https://github.com/m-creativelab/jsar-runtime/blob/main/src/xr/session.cpp)) to manage the rendering pipeline.

### Positioning Web Content in 3D Space

After establishing a session, developers position the web page within the 3D environment by updating the session’s base transformation matrix:

```cpp
auto xrSession = device->requestSession(
  xr::TrXRSessionMode::ImmersiveVR, 
  contentRuntime
);
xrSession->setLocalBaseMatrix(
  glm::translate(glm::mat4(1.0f), glm::vec3(0, 1.5f, -2))
);

```

This positions the web page 2 meters in front of the user at eye level. Internally, `setLocalBaseMatrix` updates the zone system and synchronizes spatial audio source matrices (see implementation details in [`src/xr/session.cpp`](https://github.com/m-creativelab/jsar-runtime/blob/main/src/xr/session.cpp)).

## Core Source Files for Immersive Development

Understanding these key files is essential for developers extending JSAR’s immersive capabilities:

- **[`docs/api/embedder.md`](https://github.com/m-creativelab/jsar-runtime/blob/main/docs/api/embedder.md)** – Defines the `TrEmbedder` virtual class, lifecycle hooks (`onStart`, `onBeforeRendering`), and JSON startup configuration schema.

- **[`src/xr/device.hpp`](https://github.com/m-creativelab/jsar-runtime/blob/main/src/xr/device.hpp)** – Public API for XR device configuration, session management, and handling of view/projection matrices for stereo rendering.

- **[`src/xr/session.cpp`](https://github.com/m-creativelab/jsar-runtime/blob/main/src/xr/session.cpp)** – Implements `TrXRSession` including session state management, stereo-id generation, frustum culling, and base-matrix updates that position content in world space.

- **[`src/xr/input_source.cpp`](https://github.com/m-creativelab/jsar-runtime/blob/main/src/xr/input_source.cpp)** – Handles XR input devices including controllers, gaze tracking, and hand tracking systems.

- **[`runtime/content.hpp`](https://github.com/m-creativelab/jsar-runtime/blob/main/runtime/content.hpp)** and **[`renderer/content_renderer.hpp`](https://github.com/m-creativelab/jsar-runtime/blob/main/renderer/content_renderer.hpp)** – Manage loading of HTML/CSS/JS content and batch DOM elements into optimized GPU draw calls.

- **[`common/zone.hpp`](https://github.com/m-creativelab/jsar-runtime/blob/main/common/zone.hpp)** – Persists per-session state including transformation matrices and spatial coordinates for debugging and tooling integration.

- **[`runtime/media_manager.hpp`](https://github.com/m-creativelab/jsar-runtime/blob/main/runtime/media_manager.hpp)** – Provides Web Audio API support and spatial sound sources that follow the session’s base matrix transformations.

## Summary

- JSAR bridges web technologies with native XR engines through the `TrEmbedder` C++ interface, enabling HTML content to function as interactive 3D objects.

- The architecture batches DOM rendering into ≤10 draw calls per frame while supporting multiple stereo rendering modes (Multi-Pass, Single-Pass, Instanced, Multiview).

- Web developers use standard WebXR JavaScript APIs (`navigator.xr.requestSession`) while C++ host engines control positioning via `TrXRSession::setLocalBaseMatrix` and the zone system.

- Core implementation files include [`src/xr/device.hpp`](https://github.com/m-creativelab/jsar-runtime/blob/main/src/xr/device.hpp) for device management and [`src/xr/session.cpp`](https://github.com/m-creativelab/jsar-runtime/blob/main/src/xr/session.cpp) for session lifecycle and spatial transforms.

## Frequently Asked Questions

### What is the `TrEmbedder` class in JSAR?

The `TrEmbedder` class is a C++ virtual interface defined in [`docs/api/embedder.md`](https://github.com/m-creativelab/jsar-runtime/blob/main/docs/api/embedder.md) that allows host engines (Unity, Unreal, or custom) to embed and control the JSAR runtime. It provides lifecycle hooks including `onStart` for initialization, `onBeforeRendering` for per-frame updates, and shutdown handlers for resource cleanup.

### How does JSAR handle WebXR session management?

JSAR implements the WebXR specification through the `Device` class in [`src/xr/device.hpp`](https://github.com/m-creativelab/jsar-runtime/blob/main/src/xr/device.hpp), which creates and manages `TrXRSession` objects. When JavaScript calls `navigator.xr.requestSession()`, the native `Device::requestSession` method instantiates a session that handles per-eye view matrices, projection calculations, and frustum culling as implemented in [`src/xr/session.cpp`](https://github.com/m-creativelab/jsar-runtime/blob/main/src/xr/session.cpp).

### What stereo rendering modes does JSAR support?

JSAR supports four stereo rendering modes defined in the `StereoRenderingMode` enumeration: **Multi-Pass**, **Single-Pass**, **Instanced**, and **SinglePassMultiview**. Host engines select the appropriate mode during initialization via `xr::TrDeviceInit` to optimize for their target graphics API (OpenGL, Metal, or Direct3D).

### How many draw calls does JSAR use per frame?

JSAR batches all spatialized DOM elements into **≤10 GPU draw calls per frame**, as implemented in the content renderer ([`renderer/content_renderer.hpp`](https://github.com/m-creativelab/jsar-runtime/blob/main/renderer/content_renderer.hpp)). This optimization ensures high frame rates and stable performance on mobile XR hardware while maintaining visual quality for immersive web content.