RemotionUI

Text Animator

After Effects text animator: range and wiggly selectors drive per-character, per-word or per-line position, scale, rotation, opacity, blur, tracking and fill over measured layout. Install with npx remotion-ui@latest add text-animator.

PrimitiveMotion graphicsAdvanced

text-animator30fps · 960×540
Install
$ npx remotion-ui@latest add text-animator

An animator declares what selected glyphs should become — lower, blurred, rotated, recoloured — and a selector decides how much of that each glyph gets. You animate the selector, usually its offset, so one keyframe pair moves a whole line. The preview has no per-glyph keyframes at all. Four animators overlap in time: a Smooth range passes through as a wave; a Smooth range intersected with a Wiggly selector makes a tremor that only exists inside a travelling window; a line-basis range breathes the second line's tracking; and a word-basis Triangle range leans whole words forward in turn.

Selectors. range: start / end / offset (0–1, or unit indices with units: "index"), shape (square, ramp-up, ramp-down, triangle, round, smooth), easeHigh / easeLow, smoothness, randomizeOrder + seed, amount, and a combine mode (add, subtract, intersect, min, max, difference). wiggly: minAmount / maxAmount, wigglesPerSecond, correlation, phases and seed. Ramps are one-sided as in AE, so a sweeping offset reveals a line and leaves it revealed.

Properties apply in proportion to the selection: position, scale, rotation, skew, opacity, blur, tracking, fill and characterOffset. basedOn picks the unit: characters (spaces count), characters excluding spaces, words or lines. anchorGrouping pivots scale and rotation on each glyph, its word, its line or the whole block.

Layout is measured. The component waits for the font, measures each word by its prefixes (so kerning survives), wraps without ever splitting a word, and shrinks the type only when a single word cannot fit. Animated tracking pushes real neighbours and re-centres the line. Pass waitForFont={waitUntilDone} from loadFont() so measurement waits for exactly your face; without it the component waits up to 1.5s for a loaded face of the primary family.

Long blocks stay cheap. Glyphs no animator is touching render as plain per-word text, and blurred glyphs share one filter per line and half-pixel blur step. On a 2,500-glyph block the component costs ~2ms per frame over plain text, down from ~27ms.

Usage

import { TextAnimator } from "@/remotion/primitives/text-animator";
import { easyEase } from "@/remotion/lib/ae-motion";

<TextAnimator
  text="Every letter keeps its own clock"
  animators={[
    {
      basedOn: "characters-excluding-spaces",
      properties: { position: [0, 60], rotation: 12, opacity: 0, blur: 12 },
      selectors: [
        { shape: "ramp-up", start: 0, end: 0.3, offset: [easyEase(0, -0.3), easyEase(45, 1)] },
      ],
    },
  ]}
/>
Selectors: range (start/end/offset, shape square|ramp-up|ramp-down|triangle|round|smooth, easeHigh/easeLow, randomizeOrder, mode, amount) and wiggly. Installs @remotion/layout-utils.

Agent notes

Install first, then import the copied source component locally. AI guide →

Import
@/remotion/primitives/text-animator
  • Use when: After Effects-style motion graphics built from composable, keyframeable operators.
  • Customize: text, animators, fontSize, fontFamily, plus copied source for timing, layout, colors, and typography.
  • Rule: do not import this component from the remotion-ui npm package; it is copied into your project.

Usage

Example
import { TextAnimator } from "@/remotion/primitives/text-animator"; import { easyEase } from "@/remotion/lib/ae-motion"; <TextAnimator text="Every letter keeps its own clock" animators={[ { properties: { position: [0, 60], opacity: 0, blur: 12 }, selectors: [{ shape: "ramp-up", start: 0, end: 0.3, offset: [easyEase(0, -0.3), easyEase(45, 1)] }], }, ]} />

API Reference

PropTypeDescription
text*stringCopy. \n forces a line break; words wrap at maxWidth and never split.
animatorsTextAnimatorLayer[]{ properties, selectors?, basedOn? }. Properties: position, scale, rotation, skew, opacity, blur, tracking, fill, characterOffset.
fontSizenumberDefaults to 84px at 1080 wide, scaled. Shrinks only if one word cannot fit.
fontFamilystringThe render waits for this face before measuring.
fontWeightnumberWeight used for measuring and drawing.
colorstringBase fill before any animator recolours a glyph.
lineHeightnumberMultiple of the font size.
letterSpacingnumberBase tracking in em.
align"left" | "center" | "right"Line alignment; follows animated tracking.
maxWidthnumberWrap width. Defaults to 84% of the composition width.
anchorGrouping"character" | "word" | "line" | "all"Pivot for scale and rotation.
waitForFont() => Promise<unknown>Resolves when the face is loaded — pass waitUntilDone from loadFont. Without it, waits up to 1.5s for a loaded face of the primary family.
framenumberRender this frame instead of the current one.

On this page