Custom HTML-in-canvas presentationsv4.0.456
Build a presentation that runs the entering and exiting scenes through a shader using the HTML-in-canvas APIs.
HTML-in-canvas requires Chrome Canary with chrome://flags/#canvas-draw-element enabled in the browser.
When to use this
Use this when you cannot implement the presentation in CSS.
Prefer CSS because it has wider browser support.
Concept
Remotion captures both scenes via captureElementImage() and passes them to your shader as two ElementImage handles (prevImage and nextImage) along with the transition time (0 → 1). Your shader uploads them as textures via drawElementImage() (or its WebGL/WebGPU equivalents) and writes the blended result to an offscreen WebGL2 canvas, which Remotion then composites into the frame.
You implement a single function — HtmlInCanvasShader<Props> — and pass it to makeHtmlInCanvasPresentation() to get back a TransitionPresentation constructor.
Boilerplate
my-shader.tsximport type {HtmlInCanvasShader } from '@remotion/transitions'; import {makeHtmlInCanvasPresentation } from '@remotion/transitions'; export typeMyShaderProps = {intensity ?: number; }; constVERTEX_SHADER = `#version 300 es in vec2 a_pos; out vec2 v_uv; void main() { v_uv = vec2(a_pos.x * 0.5 + 0.5, 0.5 - a_pos.y * 0.5); gl_Position = vec4(a_pos, 0.0, 1.0); }`; constFRAGMENT_SHADER = `#version 300 es precision highp float; uniform sampler2D u_prev; uniform sampler2D u_next; uniform float u_time; in vec2 v_uv; out vec4 outColor; void main() { // u_time = 1 → fully prev, u_time = 0 → fully next outColor = mix( texture(u_next, v_uv), texture(u_prev, v_uv), u_time ); }`; export constmyShader :HtmlInCanvasShader <MyShaderProps > = (canvas ) => { constgl =canvas .getContext ('webgl2', {premultipliedAlpha : true}); if (!gl ) { throw newError ('WebGL2 unavailable'); } // Compile + link program, create textures, bind a fullscreen quad... // (see "Source references" below for a full implementation) return {clear : () => {gl .clearColor (0, 0, 0, 0);gl .clear (gl .COLOR_BUFFER_BIT ); },cleanup : () => { // Release WebGL resources here },draw : ({prevImage ,nextImage ,width ,height ,time ,passedProps }) => { // Upload prevImage / nextImage to textures via gl.texElementImage2D // Set uniforms, draw the quad }, }; }; export constmyPresentation =makeHtmlInCanvasPresentation (myShader );
Use it like any other presentation:
MyComp.tsximport {linearTiming ,TransitionSeries } from '@remotion/transitions'; import {AbsoluteFill } from 'remotion'; constSceneA :React .FC = () => <AbsoluteFill style ={{backgroundColor : '#0b84f3'}} />; constSceneB :React .FC = () => <AbsoluteFill style ={{backgroundColor : 'pink'}} />; export constMyComp :React .FC = () => { return ( <TransitionSeries > <TransitionSeries .Sequence durationInFrames ={60}> <SceneA /> </TransitionSeries .Sequence > <TransitionSeries .Transition presentation ={myPresentation ({})}timing ={linearTiming ({durationInFrames : 30})} /> <TransitionSeries .Sequence durationInFrames ={60}> <SceneB /> </TransitionSeries .Sequence > </TransitionSeries > ); };
API reference
The signature of makeHtmlInCanvasPresentation() and the HtmlInCanvasShader<Props> callback contract — clear, cleanup, draw({prevImage, nextImage, width, height, time, passedProps}) — are documented on its own page.
Adapting GLSL transitions from gl-transitions.com
gl-transitions.com is a curated catalog of community-contributed fragment shaders licensed under MIT — a great starting point.
To port one to a Remotion HTML-in-canvas presentation:
ReplacegetFromColor(uv) with texture(u_prev, uv) and getToColor(uv) with texture(u_next, uv).progress to Remotion's reversed convention with float progress = 1.0 - u_time; at the top of main().transition() body inside void main() { outColor = transition(v_uv); } (with out vec4 outColor; declared).Example implementations
See the following example implementations:
zoom-blur.tsxzoom-in-out.tsx— adapted from a gl-transitions shader
See also
makeHtmlInCanvasPresentation()— API reference- HTML-in-canvas
- Custom presentations — the CSS-based path
- Contributing a new presentation