# JSAR Renderer Process and Content Process: Architecture and Roles Explained

> Understand JSAR runtime architecture. Learn the distinct roles of the JSAR renderer process for WebGL graphics and the content process for off-screen HTML rendering into textures.

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

---

**The JSAR runtime separates execution into a Renderer Process that manages the WebGL graphics pipeline and animation frames, and a Content Process that renders HTML off-screen into textures consumable by the renderer.**

The `m-creativelab/jsar-runtime` implements a dual-process architecture that isolates low-level GPU operations from HTML document processing to optimize performance in spatial computing environments. Understanding the distinct responsibilities of the **JSAR renderer process and content process** is essential for developers building applications that blend traditional web content with high-performance 3D rendering.

## Renderer Process: Graphics Pipeline and Frame Management

The **Renderer Process** manages the low-level graphics pipeline, including the **WebGL** context, animation frame scheduling, and GPU-busy notifications. This process exposes an API that the application uses to schedule drawing work and receive per-frame callbacks through the native rendering loop.

In [`lib/bindings/renderer.ts`](https://github.com/m-creativelab/jsar-runtime/blob/main/lib/bindings/renderer.ts), the implementation pulls the native **AnimationFrameListener** via `process._linkedBinding('transmute:renderer')`. When the application calls **connectRenderer()**, the listener is created and attached to the native rendering loop, after which `onready` callbacks execute. The process forwards calls to **requestAnimationFrame**, **cancelAnimationFrame**, and **requestGpuBusyCallback** to this native listener, ensuring precise synchronization with the GPU.

### Key Renderer Process Functions

- **connectRenderer()**: Initializes the native `AnimationFrameListener` and marks the renderer as ready for frame scheduling.
- **requestAnimationFrame(callback)**: Registers a callback to fire before the next frame presentation, receiving a high-resolution timestamp.
- **cancelAnimationFrame(handle)**: Stops a previously scheduled animation frame callback.
- **requestGpuBusyCallback(callback)**: Provides notifications when the GPU is under heavy load.

## Content Process: Off-Screen HTML to Texture Conversion

The **Content Process** renders HTML and DOM content off-screen, converting it into a bitmap texture that the Renderer Process displays within the 3D scene. This separation allows standard web technologies—CSS, HTML elements, and JavaScript—to generate textures without blocking the main rendering thread.

Developers access this functionality through a custom canvas context type defined in [`types/transmute-webapis.d.ts`](https://github.com/m-creativelab/jsar-runtime/blob/main/types/transmute-webapis.d.ts). When calling `canvas.getContext('jsar:htmlrenderer')`, the content process builds an off-screen HTML document, executes any embedded scripts, and produces a bitmap. The resulting texture handle is shared with the renderer process for composition into the WebGL scene.

### Creating HTML Content for 3D Display

To render HTML content as a texture, create a canvas and request the custom context:

```ts
// Create a canvas that uses the custom HTML renderer
const canvas = document.createElement('canvas');
const htmlCtx = canvas.getContext('jsar:htmlrenderer');

if (htmlCtx) {
  // Write normal HTML into the context
  htmlCtx.write(`
    <style>
      body { margin:0; display:flex; justify-content:center; align-items:center; }
      #box { width:100px; height:100px; background:red; }
    </style>
    <div id="box"></div>
  `);

  // The content process will render this HTML into a texture.
  // The texture can then be used by the renderer process.
}

```

*Source:* [`types/transmute-webapis.d.ts`](https://github.com/m-creativelab/jsar-runtime/blob/main/types/transmute-webapis.d.ts) – comment describing the `jsar:htmlrenderer` context.

## Process Interaction and Execution Flow

The **JSAR renderer process and content process** operate in a coordinated sequence to display mixed content:

1. **Startup**: The main entry point in [`lib/main.ts`](https://github.com/m-creativelab/jsar-runtime/blob/main/lib/main.ts) initializes the environment and invokes `connectRenderer()`.
2. **Renderer Ready**: `connectRenderer()` instantiates the native `AnimationFrameListener`, enabling frame callbacks.
3. **Content Creation**: Application code creates a canvas with the `jsar:htmlrenderer` context, triggering the content process to build an off-screen HTML scene.
4. **Texture Sharing**: The content process hands the rendered bitmap to the renderer process as a WebGL texture through the messaging layer.
5. **Animation Loop**: Each frame, callbacks registered via `requestAnimationFrame` execute, allowing the application to update HTML content or scene data before presentation.

The messaging layer in [`lib/bindings/messaging.ts`](https://github.com/m-creativelab/jsar-runtime/blob/main/lib/bindings/messaging.ts) and [`lib/bindings/env.ts`](https://github.com/m-creativelab/jsar-runtime/blob/main/lib/bindings/env.ts) facilitates data exchange between processes, including texture handles and synchronization signals.

## Practical Code Examples

### Scheduling Animation Frames in the Renderer Process

Use the renderer binding to synchronize updates with the display refresh rate:

```ts
import { requestAnimationFrame, cancelAnimationFrame, requestRendererReady } from 'jsar-runtime/lib/bindings/renderer';

// Wait until the renderer is ready
requestRendererReady(() => {
  // Schedule a per‑frame callback
  const handle = requestAnimationFrame((time) => {
    console.log('New frame at', time);
    // Update your scene, then request the next frame
    requestAnimationFrame(nextCallback);
  });
});

// If you need to stop the callback later
cancelAnimationFrame(handle);

```

*Source:* [`lib/bindings/renderer.ts`](https://github.com/m-creativelab/jsar-runtime/blob/main/lib/bindings/renderer.ts) – lines 14‑41, 68‑90.

### Combining Renderer and Content Processes

This example demonstrates initializing the renderer and updating HTML content every frame:

```ts
import { connectRenderer } from 'jsar-runtime/lib/bindings/renderer';
import { requestAnimationFrame } from 'jsar-runtime/lib/bindings/renderer';

connectRenderer(); // Starts the renderer process

// Create the HTML canvas once the renderer is ready
requestRendererReady(() => {
  const canvas = document.createElement('canvas');
  const htmlCtx = canvas.getContext('jsar:htmlrenderer')!;

  // Initial HTML content
  htmlCtx.write('<div id="spinner"></div>');

  // Update the HTML every frame (e.g., rotate a spinner)
  requestAnimationFrame(function animate(time) {
    const angle = (time / 1000) * 45; // 45° per second
    htmlCtx.write(`
      <style>#spinner { width:50px; height:50px; background:blue; transform:rotate(${angle}deg); }</style>
      <div id="spinner"></div>
    `);
    requestAnimationFrame(animate);
  });
});

```

## Key Source Files

The architecture relies on the following components:

- **[`lib/bindings/renderer.ts`](https://github.com/m-creativelab/jsar-runtime/blob/main/lib/bindings/renderer.ts)**: Implements the Renderer Process API, including `connectRenderer()` and animation frame management.
- **[`types/transmute-webapis.d.ts`](https://github.com/m-creativelab/jsar-runtime/blob/main/types/transmute-webapis.d.ts)**: Documents the `jsar:htmlrenderer` context type used by the Content Process.
- **[`lib/main.ts`](https://github.com/m-creativelab/jsar-runtime/blob/main/lib/main.ts)**: Entry point that initializes the environment and loads the renderer.
- **[`lib/bindings/messaging.ts`](https://github.com/m-creativelab/jsar-runtime/blob/main/lib/bindings/messaging.ts)** and **[`lib/bindings/env.ts`](https://github.com/m-creativelab/jsar-runtime/blob/main/lib/bindings/env.ts)**: Provide the messaging layer for inter-process texture and data exchange.
- **[`lib/runtime2/ResourceLoader.ts`](https://github.com/m-creativelab/jsar-runtime/blob/main/lib/runtime2/ResourceLoader.ts)**: Handles asset loading for both processes.

## Summary

- The **Renderer Process** manages the WebGL context, GPU notifications, and per-frame callbacks via the native `AnimationFrameListener` bound in [`lib/bindings/renderer.ts`](https://github.com/m-creativelab/jsar-runtime/blob/main/lib/bindings/renderer.ts).
- The **Content Process** converts HTML/DOM content into textures through the `jsar:htmlrenderer` context, enabling standard web content to render inside 3D scenes.
- **Process separation** allows GPU-intensive rendering to proceed without blocking HTML parsing or script execution, with texture sharing coordinated through the messaging layer.
- **Initialization** requires calling `connectRenderer()` before requesting animation frames or creating HTML textures.

## Frequently Asked Questions

### What is the primary role of the JSAR renderer process?

The renderer process manages the low-level graphics pipeline, including WebGL context initialization, animation frame scheduling through `requestAnimationFrame`, and GPU load monitoring. According to the `m-creativelab/jsar-runtime` source code in [`lib/bindings/renderer.ts`](https://github.com/m-creativelab/jsar-runtime/blob/main/lib/bindings/renderer.ts), it pulls the native `AnimationFrameListener` via `process._linkedBinding('transmute:renderer')` to synchronize JavaScript callbacks with the native rendering loop.

### How does the content process convert HTML to a WebGL texture?

The content process exposes a custom canvas context type called `jsar:htmlrenderer`, defined in [`types/transmute-webapis.d.ts`](https://github.com/m-creativelab/jsar-runtime/blob/main/types/transmute-webapis.d.ts). When obtained via `canvas.getContext('jsar:htmlrenderer')`, it creates an off-screen HTML document, executes scripts, and renders the result into a bitmap. This bitmap is handed to the renderer process as a texture for 3D scene composition.

### How do the renderer and content processes communicate?

The processes communicate through a messaging layer implemented in [`lib/bindings/messaging.ts`](https://github.com/m-creativelab/jsar-runtime/blob/main/lib/bindings/messaging.ts) and [`lib/bindings/env.ts`](https://github.com/m-creativelab/jsar-runtime/blob/main/lib/bindings/env.ts). This layer handles the exchange of texture handles, synchronization signals, and resource loading between the GPU-driven renderer and the HTML-focused content process.

### When should I initialize the renderer process?

Initialize the renderer process by calling `connectRenderer()` from [`lib/bindings/renderer.ts`](https://github.com/m-creativelab/jsar-runtime/blob/main/lib/bindings/renderer.ts) before attempting to schedule animation frames or create HTML content textures. The function creates the native `AnimationFrameListener` and triggers `onready` callbacks, marking the system ready for frame submission.