RVE LogoReact Video EditorDOCS
RVE SDK/Features/Keyframes

Keyframes

Animate item position, size, rotation, opacity, masks, blur, counters, and text with the keyframe engine

Keyframes animate the properties of an item over time. Each item can have a keyframes field. The field holds one list of keyframes for each animated property. Between two keyframes, the editor blends the value with an ease.

The editor player, the browser export, and the cloud renderer all read the same keyframes.

Data model

import type {
  Keyframe,
  ItemKeyframes,
  KeyframeProperty,
} from '@reactvideoeditor/react-video-editor/types';
/** One list for each animated property, sorted by frame. */
type ItemKeyframes = Partial<Record<KeyframeProperty, Keyframe[]>>;

interface Keyframe {
  id: string;
  /** The frame from the start of the item, not from the start of the video. */
  frame: number;
  /** The value at the frame. A `text` keyframe has the dummy value 0. */
  value: number;
  /** The text of a `text` keyframe. */
  text?: string;
  /** How the value moves INTO this keyframe. Default: 'linear'. */
  ease?: AnimationEaseName | 'hold';
  /** A cubic bezier [x1, y1, x2, y2] for the move INTO this keyframe. It replaces `ease`. */
  bezier?: [number, number, number, number];
}

These rules apply:

  • Before the first keyframe, the property has the value of the first keyframe.
  • After the last keyframe, the property has the value of the last keyframe.
  • If a property has no keyframes, the item uses its resting value, for example left or styles.opacity.
  • If a property does not apply to the item type, the editor ignores its keyframes.

Properties

The table shows each KeyframeProperty. The Resting value is the value when the property has no keyframes. The K column shows if the K shortcut and the Add keyframe button key the property.

PropertyLabelUnitResting valueApplies toK
leftXpxitem.leftAll itemsYes
topYpxitem.topAll itemsYes
widthWidthpxitem.widthAll itemsYes
heightHeightpxitem.heightAll itemsYes
rotationRotation°item.rotationAll itemsYes
opacityOpacity0–1styles.opacity, else 1All itemsYes
scaleScale×1 (no resting field)All itemsYes
scaleXStretch X×1Visual itemsNo
scaleYStretch Y×1Visual itemsNo
countCount—counter.value, else 0Text items with counterYes
maskCircleRadiusCircle R%150Visual itemsNo
maskCircleXCircle X%50Visual itemsNo
maskCircleYCircle Y%50Visual itemsNo
maskInsetTopInset T%0Visual itemsNo
maskInsetRightInset R%0Visual itemsNo
maskInsetBottomInset B%0Visual itemsNo
maskInsetLeftInset L%0Visual itemsNo
maskInsetRadiusCorner%0Visual itemsNo
skewXSkew X°0Visual itemsNo
skewYSkew Y°0Visual itemsNo
drawDraw% (0–100)styles.draw, else 100Arc and line shapesNo
brightnessBrightness% (−100 to 100)0Images and videosNo
blurBlurpx0Text and shapesNo
progressProgress% (0–100)particles.progress, else 100Particles shapesNo
shimmerShimmer% (0–100)particles.shimmer, else 0Particles shapesNo
textText—contentText items with no counterNo

"Visual items" are all items except audio and zoom items.

Scale, stretch, and origin

scale multiplies the size of the item on the two axes. scaleX and scaleY multiply scale on one axis. Scale, stretch, and rotation turn around the origin point. Set the origin with originX and originY on the item, in % of the item box. The default is 50 (the centre).

Masks

The mask properties clip the item. All mask values are in %.

  • Circle mask — maskCircleX and maskCircleY set the centre, in % of the item size. maskCircleRadius sets the radius. At 150, the circle covers the full item from any centre in the item.
  • Inset mask — maskInsetTop, maskInsetRight, maskInsetBottom, and maskInsetLeft cut each side, in % of the item size. A side can go down to −50 %, so the mask can show more than the item box. maskInsetRadius sets the corner radius, in % of the shorter side.

Animate a mask to make a reveal. For example, move maskInsetRight from 100 to 0 to wipe the item in from the left.

Skew, brightness, and blur

  • skewX and skewY slant the item, in degrees.
  • brightness puts a black shade (below 0) or a white shade (above 0) over an image or a video. The shade is a layer, so the browser export shows the same result as the player.
  • blur blurs text and shapes, in px.

Blur on images and videos

The browser export does not draw a blur on images and videos. For this reason, the blur property applies only to text and shapes.

Eases

The ease of a keyframe controls the move from the previous keyframe into this keyframe.

EaseMotion
linearThe same speed from start to end. This is the default.
smoothA slow start and a slow end.
outA fast start and a slow end.
whipA very slow start, a fast middle, and a very slow end.
glideA fast start and a long, soft end.
breatheA soft sine curve.
backGoes past the end value, then comes back.
springGoes past the end value and bounces a small amount before it stops.
holdNo blend. The value jumps at the keyframe.

Keyframe values are not clamped, so back and spring can go past the end value.

For a custom curve, set bezier to [x1, y1, x2, y2], the same as CSS cubic-bezier(). If bezier is set, it replaces ease. The editor UI does not set bezier. Set it in your data. If a user changes the ease of the keyframe in the editor, the editor removes bezier.

Text keyframes

The text property changes the content of a text item over time. A text keyframe holds its text in the text field. Its value is always 0.

  • Text does not blend. Each text holds until the next keyframe.
  • Text keyframes always hold, so they have no ease.
  • The text box uses the longest text for its size, so the box does not change size when the text changes.
  • If the item has a counter, the editor ignores its text keyframes.
"keyframes": {
  "text": [
    { "id": "t1", "frame": 0, "value": 0, "text": "Ready" },
    { "id": "t2", "frame": 30, "value": 0, "text": "Set" },
    { "id": "t3", "frame": 60, "value": 0, "text": "Go!" }
  ]
}

When a text item has text keyframes, the text field of the item panel edits the keyframe that holds at the playhead.

Count number

A text item with a counter shows a number in place of its content. The count keyframes animate the number.

interface TextCounter {
  /** The number when the item has no `count` keyframes. */
  value: number;
  decimals?: number;
  prefix?: string;
  suffix?: string;
  /** The thousands separator, for example ','. An empty string or no value gives none. */
  separator?: string;
  /** Shows the value as seconds in the mm:ss format. */
  clock?: boolean;
}
  • decimals can go from 0 to 6.
  • If separator is '.', the decimal mark is ','.
  • A minus sign goes before the prefix, for example -$1,200.50.
  • If clock is true, the editor rounds the value to whole seconds and shows it as mm:ss. The minutes can go past 59.

In the editor, the Count number switch in the Animate tab of a text item turns on the counter. The switch adds two count keyframes: 0 at the item start and 100 at 1 second (or at the last frame of a shorter item). The section also has Start, End, Decimals, Prefix, Suffix, Separator, and Clock controls.

Editor UI

Markers on item bars

The timeline shows a small triangle on the item bar at each frame where the item has a keyframe.

  • Click a marker to select the keyframes at that frame. The playhead moves to the frame, and the Animate tab opens.
  • Shift-click a marker to add its keyframes to the selection.
  • Drag a marker to move the selected keyframes together. The editor does not do a move that takes a keyframe out of the item or onto another keyframe of the same property.

To hide the markers, turn off Keyframe markers in the Settings panel. The setting is on by default.

Animate tab

Each item panel has an Animate tab. The tab shows the enter and exit animations, then the Keyframes section:

  • Add keyframe keys the full item at the playhead, the same as K. The playhead must be on the item.
  • The list shows the time of each keyframe. A click selects the keyframes at that time and moves the playhead to it. Shift-click adds to the selection.
  • Ease sets the ease of the selected keyframes.
  • Delete removes the selected keyframes.
  • Advanced shows one row for each property that applies to the item. Each row shows the value at the playhead and has buttons to go to the previous keyframe, add or remove a keyframe, go to the next keyframe, and clear all keyframes of the property. For a text item, the Text row comes first.

Canvas edits write keyframes

If a property has keyframes, a canvas edit writes a keyframe at the playhead. This applies to a drag, a resize, a rotation, and panel edits such as opacity.

  • If a keyframe is at the playhead, the edit changes its value. The keyframe keeps its ID and ease.
  • If no keyframe is at the playhead, the edit adds a keyframe.
  • If a property has no keyframes, the edit changes the resting value.
  • If the playhead is not on the item, an edit to a property with keyframes has no effect.

Shortcuts

KeysAction
KAdd a keyframe for the selected item at the playhead
Backspace / DeleteDelete the selected keyframes. If no keyframes are selected, delete the selected items
Alt + ← / Alt + →Go to the previous or next keyframe of the selected item
EscapeClear the keyframe selection. If no keyframes are selected, clear the item selection

See Editing and shortcuts for all shortcuts.

The disableVideoKeyframes prop

ReactVideoEditor accepts a disableVideoKeyframes prop. In the current version, this prop has no effect. The editor stores the value, but no part of the editor reads it. The prop does not turn off keyframes. It does not turn off the keyframe markers.

Example

This text item moves from the left, fades in, and grows with a custom curve:

{
  "id": "title-1",
  "type": "text",
  "from": 0,
  "durationInFrames": 90,
  "left": 100,
  "top": 450,
  "width": 600,
  "height": 180,
  "rotation": 0,
  "content": "Hello",
  "styles": {
    "fontSize": "4rem",
    "fontWeight": "700",
    "color": "#ffffff",
    "backgroundColor": "transparent",
    "fontFamily": "Inter",
    "fontStyle": "normal",
    "textDecoration": "none"
  },
  "keyframes": {
    "left": [
      { "id": "k1", "frame": 0, "value": 100 },
      { "id": "k2", "frame": 30, "value": 660, "ease": "out" }
    ],
    "opacity": [
      { "id": "k3", "frame": 0, "value": 0 },
      { "id": "k4", "frame": 20, "value": 1, "ease": "smooth" }
    ],
    "scale": [
      { "id": "k5", "frame": 0, "value": 0.8 },
      { "id": "k6", "frame": 30, "value": 1, "bezier": [0.16, 1, 0.3, 1] }
    ]
  }
}

This text item counts from 0 to 1,250 in 2 seconds at 30 fps:

{
  "type": "text",
  "content": "",
  "counter": { "value": 0, "decimals": 0, "prefix": "$", "separator": "," },
  "keyframes": {
    "count": [
      { "id": "c1", "frame": 0, "value": 0 },
      { "id": "c2", "frame": 60, "value": 1250, "ease": "out" }
    ]
  }
}

Custom compositions

If you render with your own composition, wrap each item in LayerBox. If you do not use LayerBox, keyframes do not move the items. See Custom compositions.