kinetograph.
Guides

Remotion effects

Which @remotion/effects effects Kinetograph draws, and how it runs them.

@remotion/effects is Remotion's package of shader effects (blur(), vignette(), glow()) for canvas components. Kinetograph runs the copy in your project's node_modules. It ships none of Remotion's effect code, so install the package yourself, at the same version as remotion. The package is covered by Remotion's licence, and a company may need a Remotion Company License to use it; Kinetograph ships none of its code.

import { CanvasImage } from 'remotion';
import { blur } from '@remotion/effects/blur';
import { vignette } from '@remotion/effects/vignette';

<CanvasImage src={staticFile('photo.png')} effects={[blur({ radius: 12 }), vignette()]} />;
  • effects works on every component Remotion gives it to: <Solid>, <Img>, <CanvasImage>, <AnimatedImage>, <Gif>, <Video> (from @remotion/media), <HtmlInCanvas>, Rive and the @remotion/shapes components (<Rect>, <Circle>, <Triangle>, <Star>, <Ellipse>, <Pie>, <Polygon>, <Heart>, <Arrow>, <Callout>, <Spark>). <OffthreadVideo> and <Html5Video> take none in Remotion either.
  • The canvas an effect draws on is the picture's own size: the video's or GIF's pixels, the shape's box (times pixelDensity), or effectsOutputSize. A <Video> with effects is fitted to its box with objectFit, contain by default.
  • <Video>, <Gif> and the shapes also take the engine's own effects (blur(8)) in the same array. Those apply to the finished picture, after Remotion's.
  • Most effects have a WebGPU and a WebGL 2 implementation, a few also a 2D one. Kinetograph tries WebGPU, then WebGL 2, then 2D, and uses the first that draws the frame. It warns once when it falls back. Pass --preferred-effect-backend webgpu|webgl2|2d to render, still, strip or onion to try one first. The same choice comes from window.remotion_preferredEffectBackend or a PreferredEffectBackendContext provider, as in Remotion, and the context wins over the window value. The environment variable KINETOGRAPH_PREFERRED_EFFECT_BACKEND overrides all three.
  • kinetograph doctor <entry> prints the installed @remotion/effects version, warns when it differs from the one the table below was measured with, and lists the effects your project imports that are approximated or not yet supported.
  • An effect that reads the pixels of its picture (tile(), outline(), the 2D brightness() and contrast()) makes the frame one extra draw of the layer, a few milliseconds at 960 × 540. If the pixels cannot be read, the picture is drawn without the effect and the frame reports it, so --strict fails.
  • State from setup doesn't carry to the next frame. See What works.

Status

Each effect is rendered by Remotion in Chrome and by Kinetograph, at frame 0, 960 × 540, and compared by PSNR. Supported means 50 dB or more on the backend Kinetograph picks. The table is generated from that run, with one set of parameters per effect.

89 of 89 are supported, 0 approximated, 0 not yet. Measured against Remotion 4.0.540 in Chrome.

EffectBackendsStatus
barrelDistortion()webgpu, webgl2Supported
bevelAlpha()webgpu, webgl2Supported
blur()webgpu, webgl2Supported
brightness()webgl2, webgpu, 2dSupported
burlap()webgpu, webgl2Supported
checkerboard()webgpu, webgl2Supported
chromaticAberration()webgpu, webgl2Supported
colorCorrection()webgpu, webgl2Supported
colorKey()webgpu, webgl2Supported
contourLines()webgpu, webgl2Supported
contrast()webgl2, webgpu, 2dSupported
cornerPin()webgpu, webgl2Supported
curves()webgpu, webgl2Supported
cylinder()webgpu, webgl2Supported
dotGrid()webgpu, webgl2Supported
dropShadow()webgpu, webgl2Supported
duotone()webgl2, webgpuSupported
emboss()webgl2, webgpuSupported
evolve()webgpu, webgl2Supported
exposure()webgpu, webgl2Supported
filmBurn()webgpu, webgl2Supported
fisheye()webgpu, webgl2Supported
flannel()webgpu, webgl2Supported
fractalNoise()webgpu, webgl2Supported
glow()webgpu, webgl2Supported
grayscale()webgl2, webgpu, 2dSupported
gridlines()webgpu, webgl2Supported
halftone()webgpu, webgl2Supported
halftoneLinearGradient()webgpu, webgl2Supported
hue()webgl2, webgpu, 2dSupported
invert()webgl2, webgpu, 2dSupported
irisWipe()webgpu, webgl2Supported
lensBlur()webgpu, webgl2Supported
levels()webgpu, webgl2Supported
lightLeak()webgpu, webgl2Supported
lightTrail()webgpu, webgl2Supported
linearGradient()webgl2, webgpuSupported
linearGradientTint()webgl2, webgpuSupported
linearProgressiveBlur()webgpu, webgl2Supported
linearProgressivePixelate()webgpu, webgl2Supported
lines()webgpu, webgl2Supported
liquidContours()webgpu, webgl2Supported
longShadows()webgpu, webgl2Supported
lut()webgpu, webgl2Supported
mirror()webgpu, webgl2Supported
noise()webgpu, webgl2Supported
noiseDisplacement()webgpu, webgl2Supported
outline()webgpu, webgl2Supported
pageTurn()webgpu, webgl2Supported
paper()webgpu, webgl2Supported
pattern()webgpu, webgl2Supported
pixelate()webgpu, webgl2Supported
pixelDissolve()webgpu, webgl2Supported
radialProgressiveBlur()webgpu, webgl2Supported
radialProgressivePixelate()webgpu, webgl2Supported
radialWipe()webgpu, webgl2Supported
rainFall()webgpu, webgl2Supported
regionBlur()webgpu, webgl2Supported
rings()webgpu, webgl2Supported
roughenEdges()webgpu, webgl2Supported
saturation()webgl2, webgpu, 2dSupported
scale()webgl2, webgpu, 2dSupported. The 2D backend is approximate (32 dB: the edges of thin lines are resampled a little differently); WebGPU and WebGL 2 match
scanlines()webgpu, webgl2Supported
shadowsHighlights()webgpu, webgl2Supported
shatter()webgpu, webgl2Supported. On WebGL 2 pixels on the edges of the shards differ a little (35 dB); WebGPU is used and matches
shine()webgpu, webgl2Supported
shrinkwrap()webgpu, webgl2Supported
skew()webgl2, webgpuSupported
snowFall()webgpu, webgl2Supported
speckle()webgpu, webgl2Supported
sphere()webgpu, webgl2Supported
starburst()webgpu, webgl2Supported
tear()webgpu, webgl2Supported. On WebGL 2 pixels on the tear's edge differ a little (50 dB); WebGPU is used and matches
thermalVision()webgpu, webgl2Supported
tile()webgl2, webgpu, 2dSupported
tint()webgl2, webgpu, 2dSupported
turbulentDisplace()webgpu, webgl2Supported
tvSignalOff()webgpu, webgl2Supported
uvTranslate()webgl2, webgpu, 2dSupported
venetianBlinds()webgpu, webgl2Supported
vibrance()webgpu, webgl2Supported
vignette()webgl2, webgpuSupported
wave()webgpu, webgl2Supported
waves()webgpu, webgl2Supported
whiteBalance()webgpu, webgl2Supported
whiteNoise()webgpu, webgl2Supported
xyTranslate()webgl2, webgpu, 2dSupported
zigzag()webgpu, webgl2Supported
zoomBlur()webgpu, webgl2Supported

Components

The same check on components other than <CanvasImage>: blur, grayscale and vignette in a chain (and rainFall, a heavy WebGPU effect) on an <Img>, a frame of a <Video> and two shapes, at 960 × 540. A video is compared with its colour matrix tagged (BT.709): an untagged file is read with another matrix by Chrome and Kinetograph.

CasePSNR and SSIM against RemotionStatus
<Img> with blur, grayscale, vignettewebgl2 77.0 dB, SSIM 1.000; webgpu 77.1 dB, SSIM 1.000Supported
<Video> with blur, grayscale, vignettewebgl2 53.1 dB, SSIM 0.999; webgpu 53.1 dB, SSIM 0.999Supported
<Rect> with blur, grayscale, vignettewebgl2 identical, SSIM 1.000; webgpu identical, SSIM 1.000Supported
<Star> with blur, grayscale, vignettewebgl2 76.2 dB, SSIM 1.000; webgpu 76.2 dB, SSIM 1.000Supported
<Img> with rainFallwebgl2 54.7 dB, SSIM 0.999; webgpu 78.5 dB, SSIM 1.000Supported

On this page