← Files RemotionARCHIVED FILE
skills/remotion-markup/html-in-canvas.md
2.91 KB · Oct 10, 2026 · 06:13 UTC
# Using `<HtmlInCanvas>` in Remotion
Renders children into a `<canvas>` so you can post-process them with the Canvas 2D API or WebGL.
Only works in Chrome 149+ with the `chrome://flags/#canvas-draw-element` flag enabled.
Give the user a notice.
## Nesting
Nest `<HtmlInCanvas>` components only when `HtmlInCanvas.isNestingSupported()` returns `true` (Chrome 157.0.8080.0 or newer with HTML-in-canvas enabled). Older browsers reject nesting.
## Enabling WebGL during renders
If you make use of WebGL during renders, you need to enable it:
From the CLI:
```bash
npx remotion render --gl=angle
```
Set it as the default for Studio and CLI (advised):
```ts
import { Config } from "@remotion/cli/config";
Config.setChromiumOpenGlRenderer("angle");
```
## Basic usage
By default, draws to canvas with no effect applied:
```tsx
import { HtmlInCanvas } from "remotion";
export const MyComp = () => {
return (
<HtmlInCanvas width={1280} height={720}>
<div style={{ fontSize: 80 }}>
Hello
</div>
</HtmlInCanvas>
);
};
```
## 2D effect with `onPaint`
`onPaint` runs whenever the content updates. Call `ctx.drawElementImage(elementImage, 0, 0)` to draw the captured DOM.
```tsx
import {
AbsoluteFill,
HtmlInCanvas,
type HtmlInCanvasOnPaint,
useCurrentFrame,
useVideoConfig,
} from "remotion";
import { useCallback } from "react";
export const Blur = () => {
const frame = useCurrentFrame();
const { width, height, fps } = useVideoConfig();
const onPaint: HtmlInCanvasOnPaint = useCallback(
({ canvas, elementImage }) => {
const ctx = canvas.getContext("2d");
if (!ctx) throw new Error("Failed to acquire 2D context");
const blurPx = 4 + 18 * (0.5 + 0.5 * Math.sin((frame / fps) * Math.PI));
ctx.reset();
ctx.filter = `blur(${blurPx}px)`;
ctx.drawElementImage(elementImage, 0, 0);
},
[frame, fps],
);
return (
<HtmlInCanvas width={width} height={height} onPaint={onPaint}>
<AbsoluteFill
style={{
justifyContent: "center",
alignItems: "center",
fontSize: 120,
}}
>
<h1>
Hello
</h1>
</AbsoluteFill>
</HtmlInCanvas>
);
};
```
## WebGL effects
For WebGL, set up the context, program, and texture in `onInit` and return a cleanup function. Allocate the texture with `gl.texImage2D(..., null)` when `elementImage` changes size. Inside `onPaint`, upload with `gl.texElementSubImage2D(gl.TEXTURE_2D, 0, 0, 0, elementImage)` and draw. Older Chromium versions only expose `gl.texElementImage2D()`; use it when the new method is absent.
For a fully working minimal example, see https://github.com/remotion-dev/remotion/blob/main/packages/docs/components/demos/HtmlInCanvasDocsDemoWebGL.tsx.
## Async `onPaint`
`onPaint` may be `async`. Remotion holds the frame open via `delayRender()` until the promise resolves. Useful for multi-pass effects with `createImageBitmap`.
SHA-256: 9b896dab368f8d9aec41114f8d0b96c1fbee981419b7077d6fd61621a0a54be4