Remotion Now Lets Developers Write GPU Shaders as React Video Transitions
Remotion's @remotion/transitions now supports GPU-powered WebGL shader transitions between HTML scenes, with ported gl-transitions presets included out of the box
- New capability:
@remotion/transitionsnow supports HTML-in-canvas presentations, enabling WebGL shader-based blending between React scenes. - How it works: Remotion captures both scenes as GPU textures and passes them to a user-written GLSL fragment shader via
makeHtmlInCanvasPresentation(). - New presets: Ships with
zoomBlur(),filmBurn(),ripple(),crosswarp(),swap(), and more, several ported from the MIT-licensed gl-transitions catalog. - Requirement: Needs Chrome 149+ with the
chrome://flags/#canvas-draw-elementflag enabled for preview; rendering on Lambda and Vercel is supported from v4.0.455. - API is experimental: The underlying browser API is unstable and Chrome may change or remove it in the future.
- Pricing: Free for individuals and teams up to 3; paid company licenses start at $25/seat/month for larger teams.
Remotion's transition system just got a serious upgrade. The @remotion/transitions package now supports HTML-in-canvas presentations, which means you can write WebGL fragment shaders that blend two full React scenes together, pixel by pixel, during a transition. This is a fundamentally different capability from what was possible before.
The old ceiling
Until now, Remotion's built-in transition presentations were all CSS-based: slides, wipes, flips, fades. CSS is great for layout-driven animations, but it hits a hard wall when you want effects that require per-pixel blending, like a ripple distortion, a zoom blur, or a film burn that mixes the outgoing and incoming scenes at the fragment level. Those effects simply cannot be expressed as CSS transforms or opacity changes.
The new HTML-in-canvas presentations remove that ceiling entirely.
How it actually works
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 to 1). Your shader uploads them as textures via drawElementImage() 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.
That constructor slots directly into the existing <TransitionSeries> API, so nothing about how you sequence scenes changes.
Here is the minimal crossfade shader to get a feel for the shape of the API:
import { makeHtmlInCanvasPresentation, type HtmlInCanvasShader } from '@remotion/transitions';
const FRAGMENT = `#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() {
outColor = mix(texture(u_next, v_uv), texture(u_prev, v_uv), u_time);
}`;
const myShader: HtmlInCanvasShader<{}> = (canvas) => {
const gl = canvas.getContext('webgl2', { premultipliedAlpha: true })!;
// compile shaders, bind quad...
return {
clear: () => { gl.clear(gl.COLOR_BUFFER_BIT); },
cleanup: () => { /* release GL resources */ },
draw: ({ prevImage, nextImage, time }) => {
// upload textures, set u_time uniform, draw
},
};
};
export const myPresentation = makeHtmlInCanvasPresentation(myShader);And using it in a composition is identical to any other presentation:
import { TransitionSeries, linearTiming } from '@remotion/transitions';
export const MyComp = () => (
<TransitionSeries>
<TransitionSeries.Sequence durationInFrames={60}>
<SceneA />
</TransitionSeries.Sequence>
<TransitionSeries.Transition
presentation={myPresentation({})}
timing={linearTiming({ durationInFrames: 30 })}
/>
<TransitionSeries.Sequence durationInFrames={60}>
<SceneB />
</TransitionSeries.Sequence>
</TransitionSeries>
);Ready-made presets, ported from gl-transitions
The package now ships with a set of HTML-in-canvas presentations including zoomBlur(), dreamyZoom(), filmBurn(), linearBlur(), bookFlip(), ripple(), crosswarp(), crossZoom(), and swap(), alongside the existing CSS-based presets like slide(), flip(), wipe(), and iris().
Several of these are direct ports from gl-transitions.com, a community catalog of MIT-licensed fragment shaders.
Porting a gl-transitions shader is straightforward: replace getFromColor(uv) with texture(u_prev, uv) and getToColor(uv) with texture(u_next, uv), then map the progress convention with float progress = 1.0 - u_time; at the top of main().
That is essentially the full migration path.
The catch: Chrome flag required
HTML-in-canvas is an experimental browser API available in Chrome and other Chromium-based browsers behind a flag, which allows you to draw a live DOM node into a <canvas> and post-process it with the Canvas 2D API, WebGL, or WebGPU.
To preview HTML-in-canvas effects in the Remotion Studio, use Google Chrome v149 or later and enable the flag at chrome://flags/#canvas-draw-element, then restart.
For rendering,
from v4.0.455, render is supported locally via npx remotion render and Studio, on Lambda, on Vercel, and through server-side rendering APIs.
The API is unstable, and Chrome may change or even remove it in the future. That is a real risk to weigh if you are building production pipelines around these effects today. Remotion does provide pre-rendered fallback videos in its own docs for browsers without the flag enabled, which is a good pattern to copy in your own projects.
What is now possible
The practical unlock here is that any GLSL fragment shader that blends two images can now be a Remotion transition. The gl-transitions catalog alone has dozens of effects, and the broader GLSL ecosystem is enormous. Effects that previously required compositing in a video editor or a separate rendering pipeline can now live entirely in your React component tree.
- Pixel-level blending: ripple distortions, chromatic aberration wipes, film grain burns
- GPU-accelerated: runs on WebGL2, so complex shaders stay performant even at 1080p
- Typed props: shader parameters are fully typed via
HtmlInCanvasShader<Props>, so you can expose intensity, direction, or any other uniform as a React prop - Same API surface: drops into
<TransitionSeries.Transition>exactly likeslide()orfade() - Vibe-coding friendly: Remotion explicitly calls out that these can be generated with AI coding tools, since GLSL shaders are a well-represented domain in training data
Availability and cost
Remotion is free for individuals, for-profit organizations with up to 3 employees, non-profits, and those evaluating the tool. For larger teams, paid plans include a Creators plan at $25 per seat per month and an Automators plan at $0.01 per render with a $100 monthly minimum.
The HTML-in-canvas transition feature is available now in @remotion/transitions. Install or update to the current version with:
npm i --save-exact @remotion/[email protected]Make sure to update all @remotion/* packages to the same version to avoid conflicts. The custom HTML-in-canvas presentations guide covers the full shader contract and porting instructions.