---
title: "HTML in Canvas"
description: "Use live DOM content as a texture for WebGL and canvas effects."
---

import { DocsVideo } from "/snippets/docs-video.jsx";

HTML in Canvas uses Chrome's experimental `drawElementImage()` API to copy rendered DOM content into a canvas. That canvas can become a Three.js texture or the input to a shader effect.

Use it when the visual treatment depends on both real HTML and GPU effects—for example, an interface inside a 3D device or a DOM scene passing through a distortion shader. It is an advanced, browser-dependent technique.

<DocsVideo
  title="Your dashboard, drawn as a live WebGL texture while its numbers keep updating"
  src="https://static.heygen.ai/hyperframes-oss/docs/images/showcase/html-in-canvas-demo-v2.mp4"
  poster="https://static.heygen.ai/hyperframes-oss/docs/images/showcase/html-in-canvas-demo-v2.jpg"
/>

The left panel is ordinary HTML and CSS. The right is the same pixels inside a
WebGL scene — bent and lit by a shader, while the DOM underneath keeps changing
and the texture re-captures every frame.

## Start with a proven block

The fastest path is to install a Catalog block that already handles capability detection and fallback behavior:

```bash
npx hyperframes add vfx-iphone-device
```

Other relevant examples include [Portal](/catalog/blocks/vfx-portal), [Shatter](/catalog/blocks/vfx-shatter), and [Liquid Glass Notification](/catalog/blocks/liquid-glass-notification).

Install every block tagged `html-in-canvas` only when you want to compare the full set:

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

## Browser support

`drawElementImage()` is an experimental Chromium feature. The feature flag only works in browser builds that contain the API.

HyperFrames enables `CanvasDrawElement` when it launches Chrome and checks whether the API is actually available. The render engine can fall back to its normal capture path when the fast-capture API is unavailable or unsafe for a composition.

To refresh the browser used by the CLI:

```bash
npx hyperframes browser ensure --force
```

For a normal browser preview, enable `chrome://flags/#canvas-draw-element` in a compatible Chrome or Brave build and restart it. Keep a visual fallback because collaborators may open the composition in a browser without the feature.

## Minimal pattern

```html
<canvas id="capture" layoutsubtree width="1920" height="1080">
  <section id="source">
    <h1>Revenue: $4.2M</h1>
  </section>
</canvas>

<canvas id="scene" width="1920" height="1080"></canvas>
```

```javascript
var captureCanvas = document.getElementById("capture");
var source = document.getElementById("source");
var captureContext = captureCanvas.getContext("2d");

function supportsHtmlInCanvas() {
  var probe = document.createElement("canvas");
  probe.setAttribute("layoutsubtree", "");
  var context = probe.getContext("2d");

  return "layoutSubtree" in probe && typeof context?.drawElementImage === "function";
}

if (supportsHtmlInCanvas()) {
  captureContext.drawElementImage(source, 0, 0, 1920, 1080);
} else {
  // Draw a simpler canvas version or use a static image.
}
```

After capture, use `captureCanvas` like any other canvas texture:

```javascript
var texture = new THREE.CanvasTexture(captureCanvas);
var material = new THREE.MeshBasicMaterial({ map: texture });
```

If the DOM changes, capture it again and set `texture.needsUpdate = true`.

## Know the limits

The browser's paint-record path does not reproduce every compositor effect. Filters, backdrop filters, some 3D transforms, masks, blend modes, and similar effects can force HyperFrames back to the normal capture path.

That fallback protects the final result, but it also means HTML in Canvas is not a promise of universal CSS support or faster rendering. Test the actual composition:

```bash
npx hyperframes lint
npx hyperframes check
npx hyperframes render --output html-in-canvas.mp4
```

Review transition frames and effects in the rendered file, not only in a live preview.

## Related topics

<CardGroup cols={2}>
  <Card title="Shader transitions" icon="wand-magic-sparkles" href="/packages/shader-transitions">
    Apply built-in WebGL transitions between scenes.
  </Card>
  <Card title="Browse visual blocks" icon="grid-2" href="/catalog">
    Start from a working effect instead of rebuilding its capture logic.
  </Card>
</CardGroup>
