---
title: "HTML-in-Canvas"
description: "Render live HTML as WebGL textures — GPU shaders, 3D geometry, and cinematic effects on any DOM content."
---

# HTML-in-Canvas

The HTML-in-Canvas API (`drawElementImage`) lets you capture live, rendered DOM elements directly into a canvas at GPU speed. This means you can take any HTML — dashboards, forms, landing pages, app UIs — and render them as textures in WebGL scenes with shaders, 3D transformations, and post-processing effects.

<Warning>
**Chrome flag required.** The `drawElementImage` API is experimental and must be enabled manually:

1. Open `chrome://flags/#canvas-draw-element` in Chrome or Brave
2. Set **CanvasDrawElement** to **Enabled**
3. Restart the browser

HyperFrames enables this flag automatically during rendering (`--enable-features=CanvasDrawElement`), so rendered videos work without manual setup. The flag is only needed for live preview in the Studio.
</Warning>

## How it works

1. Place HTML content inside a `<canvas layoutsubtree>` element
2. The browser renders the HTML children as normal DOM
3. Call `ctx.drawElementImage(element, x, y, w, h)` to capture the rendered pixels into the canvas
4. Use the canvas as a Three.js texture, apply shaders, map to 3D geometry

```html
<!-- 1. HTML content lives inside the canvas -->
<canvas id="capture" layoutsubtree width="1920" height="1080">
  <div class="my-dashboard">
    <h1>Revenue: $4.2M</h1>
    <div class="chart">...</div>
  </div>
</canvas>

<!-- 2. WebGL canvas for 3D rendering -->
<canvas id="theater" width="1920" height="1080"></canvas>
```

```javascript
// 3. Capture HTML to canvas
var capCanvas = document.getElementById("capture");
var ctx = capCanvas.getContext("2d");
ctx.drawElementImage(capCanvas.querySelector(".my-dashboard"), 0, 0, 1920, 1080);

// 4. Use as Three.js texture
var texture = new THREE.CanvasTexture(capCanvas);
var material = new THREE.MeshBasicMaterial({ map: texture });
```

## What makes this different

Traditional approaches like `html2canvas` re-parse and re-render the DOM in JavaScript — they're slow, lossy, and miss CSS features like `backdrop-filter`, complex shadows, and web fonts. The `drawElementImage` API uses the browser's own compositor, so:

- **Pixel-perfect** — every CSS feature is supported because the browser renders it natively
- **GPU-accelerated** — captures at 60fps, fast enough for real-time animation
- **Live content** — the HTML can animate, scroll, and change between captures
- **Multiple captures simultaneously** — no nesting restrictions, multiple `<canvas layoutsubtree>` elements can capture different content in the same composition

## Feature detection

Always feature-detect before using the API. Compositions should fall back gracefully for browsers without the flag enabled.

```javascript
function isSupported() {
  var tc = document.createElement("canvas");
  if (!("layoutSubtree" in tc)) return false;
  tc.setAttribute("layoutsubtree", "");
  var ctx = tc.getContext("2d");
  return ctx && typeof ctx.drawElementImage === "function";
}

if (isSupported()) {
  ctx.drawElementImage(element, 0, 0, w, h);
} else {
  // Fallback: draw text directly on canvas, use static image, etc.
}
```

## Re-capturing every frame

For animated content (scrolling, transitions, counters), call `drawElementImage` inside your render loop to update the texture every frame:

```javascript
function render() {
  // Update HTML state
  scrollContainer.style.transform = "translateY(-" + scrollOffset + "px)";
  counterEl.textContent = Math.round(currentValue);

  // Re-capture
  ctx.clearRect(0, 0, W, H);
  ctx.drawElementImage(htmlElement, 0, 0, W, H);
  texture.needsUpdate = true;

  // Render 3D scene with updated texture
  renderer.render(scene, camera);
}
```

## Catalog blocks

Install all HTML-in-Canvas blocks at once:

```bash
npx hyperframes add html-in-canvas
```

Or install individually:

| Block | Description | Install |
|-------|-------------|---------|
| [iOS 26 Liquid Glass Home Screen](/catalog/blocks/ios26-liquid-glass) | iPhone home screen with live Liquid Glass notifications and widgets | `npx hyperframes add ios26-liquid-glass` |
| [macOS Tahoe Liquid Glass Desktop](/catalog/blocks/macos-tahoe-liquid-glass) | MacBook desktop with liquid glass windows, dock, and notifications | `npx hyperframes add macos-tahoe-liquid-glass` |
| [Liquid Glass Notification](/catalog/blocks/liquid-glass-notification) | Native-feeling glass notification stack with progress and reply states | `npx hyperframes add liquid-glass-notification` |
| [iPhone & MacBook](/catalog/blocks/vfx-iphone-device) | Real 3D GLTF devices with live HTML screens | `npx hyperframes add vfx-iphone-device` |
| [Text Cursor](/catalog/blocks/vfx-text-cursor) | Dramatic text reveal with chromatic shadows | `npx hyperframes add vfx-text-cursor` |
| [Portal](/catalog/blocks/vfx-portal) | Dimension breach with volumetric light | `npx hyperframes add vfx-portal` |
| [Shatter](/catalog/blocks/vfx-shatter) | HTML shatters into glass fragments | `npx hyperframes add vfx-shatter` |
| [Magnetic](/catalog/blocks/vfx-magnetic) | Magnetic field particle visualization | `npx hyperframes add vfx-magnetic` |
| [Liquid Background](/catalog/blocks/vfx-liquid-background) | Organic liquid simulation | `npx hyperframes add vfx-liquid-background` |

## Rendering

HyperFrames enables the Chrome flag automatically during rendering. No special configuration needed:

```bash
npx hyperframes render --output my-video.mp4
```

For Docker renders, the flag is also enabled automatically inside the container.
