remocn logoremocn

Typewriter

Character-by-character text reveal with a deterministic blinking cursor.

A typography primitive that reveals text one character at a time using interpolate and substring. The cursor blinks via integer math on the current frame, so it stays consistent across re-renders.

Installation

$ pnpm dlx shadcn@latest add @remocn/typewriter

Usage

// src/Root.tsx
import { Composition } from "remotion";
import { Typewriter } from "@/components/remocn/typewriter";

const TypewriterScene = () => (
  <Typewriter text="Hello, world" speed={20} fontSize={72} />
);

export const RemotionRoot = () => (
  <Composition
    id="Typewriter"
    component={TypewriterScene}
    durationInFrames={120}
    fps={30}
    width={1280}
    height={720}
  />
);

Props

PropTypeDefaultDescription
textrequired
stringThe text to type out.
cursor
booleantrueWhether to render the blinking cursor at the end.
speed
number20Typing speed in characters per second.
fontSize
number48Font size in pixels.
fontWeight
number600CSS font-weight.
color
string"#171717"Text color (any valid CSS color).
cursorColor
string"#171717"Color of the blinking cursor block.
className
stringOptional className passed to the underlying span.

Notes

Deterministic blink

The cursor uses Math.floor(frame / 15) % 2 === 0 instead of setInterval or Math.random(). This is required for Remotion: every frame must be a pure function of frame, otherwise the rendered video will glitch.

Composition length

Make sure your composition's durationInFrames is long enough to fit text.length / speed seconds of typing plus a hold at the end.