What Is the OpenMAIC Render-Service Container and How Does It Work?

The render-service container is an isolated micro-service that converts browser-generated Hyperframes projects into downloadable MP4 videos using Chromium and FFmpeg.

The render-service container in OpenMAIC offloads CPU-intensive video rendering from the main Next.js application to keep the core platform lightweight. When users click "Export Video" in the browser, this dedicated Docker worker processes the conversion, while remaining entirely optional—if disabled, the system seamlessly falls back to ZIP downloads for local CLI rendering.

Architecture and Core Purpose

The primary role of the render-service is to act as a dedicated video-rendering worker that isolates heavyweight native dependencies from the web application. As defined in docker-compose.yml, the container bundles Chromium (to load and play the Hyperframes bundle) and FFmpeg (to encode the raw frames into H.264 video).

This isolation is architectural. Chromium and FFmpeg introduce significant binary size, memory footprint, and security surface area. By confining these to a separate service, the main OpenMAIC app avoids bloat while the render-service runs in an isolated network with restricted egress policies.

Security and Network Isolation

The container launches with the NET_ADMIN Linux capability to enforce strict egress lockdown, preventing the Chromium instance from initiating unauthorized outbound connections during rendering. This security model is implemented in render-service/docker-entrypoint.sh and documented in render-service/README.md.

How the Render-Service Fits into the Export Workflow

The video export process follows a three-stage pipeline bridging browser-side generation with containerized encoding.

Step 1: Browser Bundle Generation

When a user selects "Export Video", the OpenMAIC front-end first constructs a self-contained Hyperframes bundle entirely within the browser. This JSON payload encapsulates all project assets, animation keyframes, and timing metadata required for deterministic frame-by-frame rendering.

Step 2: Service Communication via RENDER_SERVICE_URL

The main application communicates with the render-service through the RENDER_SERVICE_URL environment variable, which defaults to http://render-service:9000 as configured in docker-compose.yml. The helper function resolveRenderServiceUrl() in lib/server/render-service.ts centralizes this resolution:

import { resolveRenderServiceUrl } from '@/lib/server/render-service';

// Build URL to the render‑service endpoint
const url = `${resolveRenderServiceUrl()}/render/submit`;

// `hyperframeBundle` is the JSON produced by the browser
await fetch(url, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ bundle: hyperframeBundle })
});

Step 3: Video Encoding Pipeline

Upon receiving the bundle at /render/submit, the container loads the project into headless Chromium to capture sequential frames, then pipes the raw video stream through FFmpeg for MP4 encoding. The final video is returned to the main application or uploaded to cloud storage, depending on the deployment topology described in packages/docs/content/docs/deployment.mdx.

Configuration and Runtime Options

The behavior of the render-service is tunable through environment variables documented in render-service/README.md and packages/docs/content/docs/configuration.mdx:

  • RENDER_SERVICE_URL: The internal endpoint used by the Next.js app to reach the service (default: http://render-service:9000)
  • RENDER_MAX_CONCURRENCY: Limits parallel rendering jobs to prevent resource exhaustion
  • Timeout variables: Configure maximum waiting periods for Chromium startup and frame capture completion

Fallback Behavior When the Service Is Unavailable

Because the render-service is optional, OpenMAIC implements graceful degradation. If RENDER_SERVICE_URL is undefined or the container is unreachable, the application falls back to offering a ZIP download of the Hyperframes project:

if (!process.env.RENDER_SERVICE_URL) {
  // Offer a ZIP download instead of MP4 rendering
  const zipUrl = await generateProjectZip(bundle);
  window.location.href = zipUrl;
}

Users can then render the video locally using the OpenMAIC CLI, maintaining full functionality even in lightweight or air-gapped deployments.

Testing and CLI Usage

Developers can interact with the container directly through its CLI interface, as demonstrated in the continuous integration suite. The file tests/workflows/ci-video-export-contract.test.ts exercises the rendering pipeline using the following pattern:


# Inside the repo root

npx render-service submit path/to/hyperframe-bundle.json

This command submits a bundle directly to the service, bypassing the Next.js API layer, which is useful for debugging rendering issues or batch-processing videos via CI/CD pipelines.

Summary

  • The render-service container is an isolated micro-service in OpenMAIC that converts Hyperframes bundles to MP4 videos using Chromium and FFmpeg.
  • It communicates with the main app via the RENDER_SERVICE_URL environment variable, defaulting to http://render-service:9000 as configured in docker-compose.yml.
  • The service is optional; when disabled, OpenMAIC falls back to ZIP downloads for local CLI rendering.
  • Security hardening includes the NET_ADMIN capability and network isolation defined in render-service/docker-entrypoint.sh.
  • Configuration options like RENDER_MAX_CONCURRENCY control resource utilization and queue management.

Frequently Asked Questions

What happens if the render-service container is not running?

If the container is unavailable or RENDER_SERVICE_URL is not set, OpenMAIC automatically falls back to generating a ZIP download of the Hyperframes project. Users can then render the video locally using the OpenMAIC CLI tools without requiring the containerized service.

Why is the render-service separated from the main Next.js application?

The service isolates Chromium and FFmpeg, which are heavyweight native dependencies with large binary footprints and complex security requirements. Running them in a separate container keeps the core web application lightweight and reduces the attack surface for browser-based exploits.

How does OpenMAIC securely handle user content in the render-service?

The container launches with the NET_ADMIN Linux capability to enforce egress lockdown, preventing the Chromium instance from accessing external networks during rendering. This security model is implemented in render-service/docker-entrypoint.sh and described in the service's README.

Can I use the render-service CLI independently of the web interface?

Yes. The container exposes a CLI interface accessible via npx render-service submit, as tested in tests/workflows/ci-video-export-contract.test.ts. This allows direct submission of Hyperframes bundles for headless video generation without using the browser-based export button.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →