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()]} />;effectsworks on every component Remotion gives it to:<Solid>,<Img>,<CanvasImage>,<AnimatedImage>,<Gif>,<Video>(from@remotion/media),<HtmlInCanvas>, Rive and the@remotion/shapescomponents (<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), oreffectsOutputSize. A<Video>with effects is fitted to its box withobjectFit,containby default. <Video>,<Gif>and the shapes also take the engine's owneffects(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|2dtorender,still,striporonionto try one first. The same choice comes fromwindow.remotion_preferredEffectBackendor aPreferredEffectBackendContextprovider, as in Remotion, and the context wins over the window value. The environment variableKINETOGRAPH_PREFERRED_EFFECT_BACKENDoverrides all three. kinetograph doctor <entry>prints the installed@remotion/effectsversion, 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 2Dbrightness()andcontrast()) 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--strictfails. - State from
setupdoesn'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.
| Effect | Backends | Status |
|---|---|---|
barrelDistortion() | webgpu, webgl2 | Supported |
bevelAlpha() | webgpu, webgl2 | Supported |
blur() | webgpu, webgl2 | Supported |
brightness() | webgl2, webgpu, 2d | Supported |
burlap() | webgpu, webgl2 | Supported |
checkerboard() | webgpu, webgl2 | Supported |
chromaticAberration() | webgpu, webgl2 | Supported |
colorCorrection() | webgpu, webgl2 | Supported |
colorKey() | webgpu, webgl2 | Supported |
contourLines() | webgpu, webgl2 | Supported |
contrast() | webgl2, webgpu, 2d | Supported |
cornerPin() | webgpu, webgl2 | Supported |
curves() | webgpu, webgl2 | Supported |
cylinder() | webgpu, webgl2 | Supported |
dotGrid() | webgpu, webgl2 | Supported |
dropShadow() | webgpu, webgl2 | Supported |
duotone() | webgl2, webgpu | Supported |
emboss() | webgl2, webgpu | Supported |
evolve() | webgpu, webgl2 | Supported |
exposure() | webgpu, webgl2 | Supported |
filmBurn() | webgpu, webgl2 | Supported |
fisheye() | webgpu, webgl2 | Supported |
flannel() | webgpu, webgl2 | Supported |
fractalNoise() | webgpu, webgl2 | Supported |
glow() | webgpu, webgl2 | Supported |
grayscale() | webgl2, webgpu, 2d | Supported |
gridlines() | webgpu, webgl2 | Supported |
halftone() | webgpu, webgl2 | Supported |
halftoneLinearGradient() | webgpu, webgl2 | Supported |
hue() | webgl2, webgpu, 2d | Supported |
invert() | webgl2, webgpu, 2d | Supported |
irisWipe() | webgpu, webgl2 | Supported |
lensBlur() | webgpu, webgl2 | Supported |
levels() | webgpu, webgl2 | Supported |
lightLeak() | webgpu, webgl2 | Supported |
lightTrail() | webgpu, webgl2 | Supported |
linearGradient() | webgl2, webgpu | Supported |
linearGradientTint() | webgl2, webgpu | Supported |
linearProgressiveBlur() | webgpu, webgl2 | Supported |
linearProgressivePixelate() | webgpu, webgl2 | Supported |
lines() | webgpu, webgl2 | Supported |
liquidContours() | webgpu, webgl2 | Supported |
longShadows() | webgpu, webgl2 | Supported |
lut() | webgpu, webgl2 | Supported |
mirror() | webgpu, webgl2 | Supported |
noise() | webgpu, webgl2 | Supported |
noiseDisplacement() | webgpu, webgl2 | Supported |
outline() | webgpu, webgl2 | Supported |
pageTurn() | webgpu, webgl2 | Supported |
paper() | webgpu, webgl2 | Supported |
pattern() | webgpu, webgl2 | Supported |
pixelate() | webgpu, webgl2 | Supported |
pixelDissolve() | webgpu, webgl2 | Supported |
radialProgressiveBlur() | webgpu, webgl2 | Supported |
radialProgressivePixelate() | webgpu, webgl2 | Supported |
radialWipe() | webgpu, webgl2 | Supported |
rainFall() | webgpu, webgl2 | Supported |
regionBlur() | webgpu, webgl2 | Supported |
rings() | webgpu, webgl2 | Supported |
roughenEdges() | webgpu, webgl2 | Supported |
saturation() | webgl2, webgpu, 2d | Supported |
scale() | webgl2, webgpu, 2d | Supported. The 2D backend is approximate (32 dB: the edges of thin lines are resampled a little differently); WebGPU and WebGL 2 match |
scanlines() | webgpu, webgl2 | Supported |
shadowsHighlights() | webgpu, webgl2 | Supported |
shatter() | webgpu, webgl2 | Supported. On WebGL 2 pixels on the edges of the shards differ a little (35 dB); WebGPU is used and matches |
shine() | webgpu, webgl2 | Supported |
shrinkwrap() | webgpu, webgl2 | Supported |
skew() | webgl2, webgpu | Supported |
snowFall() | webgpu, webgl2 | Supported |
speckle() | webgpu, webgl2 | Supported |
sphere() | webgpu, webgl2 | Supported |
starburst() | webgpu, webgl2 | Supported |
tear() | webgpu, webgl2 | Supported. On WebGL 2 pixels on the tear's edge differ a little (50 dB); WebGPU is used and matches |
thermalVision() | webgpu, webgl2 | Supported |
tile() | webgl2, webgpu, 2d | Supported |
tint() | webgl2, webgpu, 2d | Supported |
turbulentDisplace() | webgpu, webgl2 | Supported |
tvSignalOff() | webgpu, webgl2 | Supported |
uvTranslate() | webgl2, webgpu, 2d | Supported |
venetianBlinds() | webgpu, webgl2 | Supported |
vibrance() | webgpu, webgl2 | Supported |
vignette() | webgl2, webgpu | Supported |
wave() | webgpu, webgl2 | Supported |
waves() | webgpu, webgl2 | Supported |
whiteBalance() | webgpu, webgl2 | Supported |
whiteNoise() | webgpu, webgl2 | Supported |
xyTranslate() | webgl2, webgpu, 2d | Supported |
zigzag() | webgpu, webgl2 | Supported |
zoomBlur() | webgpu, webgl2 | Supported |
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.
| Case | PSNR and SSIM against Remotion | Status |
|---|---|---|
<Img> with blur, grayscale, vignette | webgl2 77.0 dB, SSIM 1.000; webgpu 77.1 dB, SSIM 1.000 | Supported |
<Video> with blur, grayscale, vignette | webgl2 53.1 dB, SSIM 0.999; webgpu 53.1 dB, SSIM 0.999 | Supported |
<Rect> with blur, grayscale, vignette | webgl2 identical, SSIM 1.000; webgpu identical, SSIM 1.000 | Supported |
<Star> with blur, grayscale, vignette | webgl2 76.2 dB, SSIM 1.000; webgpu 76.2 dB, SSIM 1.000 | Supported |
<Img> with rainFall | webgl2 54.7 dB, SSIM 0.999; webgpu 78.5 dB, SSIM 1.000 | Supported |