kinetograph.
Guides

Authoring

Write a Kinetograph project with compositions, Remotion APIs, native elements, effects, fonts and assets.

A project is a TypeScript or TSX file. It draws each frame from the frame number and the props it is given. This page covers what a project can use. For the first steps, see First video.

Compositions

The entry file calls registerRoot with a function that returns one or more Compositions:

registerRoot(() => (
  <Composition id="Card" component={Card} durationInFrames={60} fps={30} width={640} height={360} />
));
PropMeaning
idThe name that --comp selects. Without --comp, the first composition is used.
componentThe component that draws a frame.
durationInFrames, fps, width, heightThe length, frame rate and size.
defaultPropsThe props used when --props does not set them.
backgroundThe background colour of every frame. The default is transparent.
marginThe least margin, in pixels, around the canvas for effects that draw past its edge.

--props takes a JSON object. The component gets defaultProps with the --props values merged over them. getInputProps() returns the --props object.

npx kinetograph render src/index.tsx --comp Card --props '{"title":"Hello"}'

Remotion APIs

Import the API from @kinetographdev/core, which comes with npm install kinetograph. It includes Remotion's names. A Remotion project keeps its remotion and @remotion/* imports, and the CLI maps them onto the same code.

Most projects use these:

  • Time: useCurrentFrame, useVideoConfig, Sequence, Series, Loop, Freeze.
  • Motion: interpolate, interpolateColors, spring, Easing.
  • Layout and files: AbsoluteFill, Img, staticFile, delayRender.
  • Random values: random(seed). The same seed gives the same value every time.

What works lists what is supported. To move a project, see Migrate from Remotion.

Determinism

A frame is a function of the frame number. Date.now(), Math.random(), timers and requestAnimationFrame follow the frame clock, not the real one. Use random('name') for a value that must be the same in every render. Do not read the system time.

Native elements

These elements come from @kinetographdev/core. They draw in the engine, not in the DOM.

ElementDraws
LayerA group of layers. Takes layout for flexbox and preserve3d for 3D.
Rect, Ellipse, Shape, PathShapes, with fill, stroke and, for Rect, radius.
TextText in a registered font. Takes font, size, color, maxWidth, align and chars.
ImageA PNG or JPEG.
Noise, MeshGradientNoise and mesh gradients.
CanvasA Canvas 2D drawing, made in draw(ctx).
GlslShaderA GLSL fragment shader, with uniforms.
LottieA Lottie animation, from src or animationData.
CameraThe perspective for 3D turns.
Scene3D, Camera3D, lights, Mesh, Model, Extrude, Text3DThe 3D layer.
Video, OffthreadVideo, Audio, GifVideo, GIF and sound files.

Every element takes the common props: id, x, y, scale, rotation, anchorX, anchorY, rotateX, rotateY, z, opacity, blendMode, effects, clip, mask, matte and motionBlur. The full table is in AUTHORING.md, section 6.3.

A shape with a gradient fill and a drop shadow:

import { Rect, dropShadow, linearGradient } from '@kinetographdev/core';

<Rect
  width={220}
  height={300}
  fill={linearGradient(['#fafafa', '#d9d9d9'], { angle: 160 })}
  effects={[dropShadow({ y: 8, blur: 12, color: '#00000030' })]}
/>

Raw text outside Text is an error. A Text layer with no registered font also fails the render.

Effects

Pass effects as effects={[...]} on any layer. They run in order on the layer's own pixels, before the layer is blended.

Blur and glow (blur, backdropBlur, glow), shadows (dropShadow, insetShadow), colour (saturate, contrast, grayscale, gradientMap, lut and others) and texture (grain, dither, halftone, displace, cornerPin, shader and others) are built in.

npx kinetograph effects lists each effect with its parameters. linearGradient, radialGradient and conicGradient work as fills and as text colours.

Fonts

A text layer uses a font by family name. Register the font before the text uses it.

Google Fonts download once and are kept in ~/.cache/kinetograph/fonts:

import { loadFont } from '@remotion/google-fonts/Inter';

const { fontFamily } = loadFont('normal', { weights: ['400'] });

For a font file in the project, use loadFont from @remotion/fonts, with staticFile for the path. Then use font="Brand" on a Text element:

import { loadFont } from '@remotion/fonts';
import { staticFile } from 'remotion';

loadFont({ family: 'Brand', url: staticFile('fonts/DMSans-Medium.ttf') });

Assets

staticFile('name') gives the path of a file in public/, next to the entry. If there is no public/ folder there, it looks next to the nearest package.json. The src of Image, Video, Audio and Gif takes these paths. See Project layout.

Canvas and shaders

Canvas runs draw(ctx) with a fresh Canvas 2D context on every frame. What it paints must come from the props and the frame, not from what was painted before.

GlslShader takes a fragment shader in GLSL ES 100 or 300 es. Compute its uniforms from the frame, for example uniforms={{ time: frame / fps }}.

See AUTHORING.md, sections 6.5 and 6.7, and What works.

2.5D and 3D

For depth without a 3D scene, put a Camera in the composition and turn a Layer with rotateX or rotateY. Set preserve3d on the layer that holds the turned children:

For example, <Camera perspective={1400} /> with <Layer rotateY={spin} preserve3d>.

For a full 3D scene, use Scene3D, Camera3D, the lights and Mesh or Model. Rotations there are in degrees. See AUTHORING.md, section 6.6. Groups that intersect in 3D are drawn in painter's order; see What works.

To check your work as you write, see First video and the CLI reference.

On this page