kinetograph.

Remotion compatibility

What works when you render a Remotion project with Kinetograph, what happens to things the engine can't draw, and how to check a project first.

Kinetograph renders Remotion projects without a browser. Your remotion and @remotion/* imports run on Kinetograph's own version of those packages, and the engine draws every frame itself.

Most projects just work. When something can't be drawn, Kinetograph tells you. For a package-by-package list with export counts, and the steps to move a project, see Migrate from Remotion.

What happens to things the engine can't draw

The engine skips them or draws something close, and prints a warning. It never switches to a browser.

  • Skipped: the frame is drawn without the item.
  • Approximated: the frame is drawn with something close to the item.
  • Warned: after drawing, render, still and strip print one line for each kind of problem. Each line names the element, the property, the reason and the frames it happened on. At most 12 lines are shown, and nothing is printed if there were no problems.

The warning only appears on frames where the element is actually on screen. Elements with display: none or visibility: hidden are not checked.

Make unsupported content an error with --strict

render, still and strip accept --strict. With it, the first frame that has anything unsupported stops the command with the error code UNSUPPORTED_CONTENT. The error exits with code 1, names the frame, and lists up to five items. A render that stops this way leaves no output file.

Use --strict in CI and for final renders, so you never ship a video with something missing. Without it, you get a video that may be slightly off, which is often more useful while you work.

--strict does not compare your video with Chrome. It only checks whether anything unsupported was used.

Check a project before you render

  • kinetograph doctor <entry> goes through every frame without using the GPU. It reports what the engine can't draw and on which frames. Run it before a long render. If the project imports a package Kinetograph doesn't support, such as @remotion/three, doctor lists each import and the file that has it, and still checks the frames it can.
  • kinetograph lint adds one warning per problem, with rule compat. The frame still renders.
  • Both are also MCP tools. The doctor tool takes the same arguments, and still, strip and render take strict.

bench, onion and snapshot draw frames as they are and do not warn. The studio shows a frame's unsupported items as a warning.

What works

These packages and APIs are supported. Gaps are listed in Known issues.

  • @remotion/transitions: all 19 presentations and useTransitionProgress.
  • @remotion/light-leaks, @remotion/starburst, @remotion/sfx, zod-types, timeline-utils, and canvas (Canvas 2D).
  • @remotion/media-utils audio: getAudioData, useAudioData, useWindowedAudioData, getAudioDurationInSeconds, visualizeAudio and getWaveformPortion. visualizeAudio follows Remotion's documented behaviour, but its numbers are not identical.
  • <Audio> and <Video> from @remotion/media.
  • toneFrequency on <Audio> and <Video>, from 0.01 to 2. It changes the pitch and keeps the length.
  • @remotion/media-parser and @remotion/webcodecs: partly supported.
  • @remotion/skia and @remotion/rive: run through optional add-ons, with gaps.

Plain HTML and SVG elements can sit next to Kinetograph's own elements in the same tree. You don't switch compatibility on.

Things your project can use as it is

  • import './index.css' works. Local @imports in the file are inlined. Tailwind is built with your project's own Tailwind setup. *.module.css files export their scoped class names.
  • The entry file runs even when package.json has a "sideEffects" list that leaves it out, as Remotion's templates do.
  • staticFile reads public/ next to the entry. If there is none, it reads public/ next to the nearest package.json, which is Remotion's rule when the entry is in src/.
  • Fonts load from their files, whether you add them with new FontFace(...) and document.fonts.add(face) or with an @font-face rule. One file is kept for each family, weight and style. If a font is split by unicodeRange, the part covering basic Latin is used. WOFF and WOFF2 files are unpacked.
  • Kinetograph reads no fonts from your system, so a render looks the same on every machine. If your project loads no font, text is drawn in DM Sans, a font that ships with Kinetograph, and the warning and doctor say so (font-family, "font not loaded; drawn with the built-in fallback"). SVG <text> is covered too.

Layout of HTML content

CSS lays out HTML content the same way a browser would, with a few rules to know:

  • A group of HTML elements is laid out as a box the size of the composition, as Remotion's root div is.
  • An <AbsoluteFill> or <Sequence> around HTML is an absolutely positioned column flex div, as in Remotion.
  • HTML inside a Kinetograph layer is laid out in the composition's box. It does not know the layer's own size.
  • A Kinetograph element inside HTML takes the size of its own box. A layer with no box, such as a group without layout, is 0 × 0.
  • Styles are read on every frame, so animation comes from your component re-rendering, as in Remotion. CSS @keyframes follow the frame's time.
  • A layer made from an HTML node takes its id attribute as its layer id if that is a valid id. Otherwise it gets where the node sits in the page, such as $0.2.

Details

On this page