entrances

Typewriter

Character-by-character text reveal with an optional blinking cursor in the Onda accent. Linear pacing by design — the one intentional exception to the house spring rule, because typing has its own constant rhythm.

$ npx ondajs add typewriter

Typewriter

A character-by-character text reveal with an optional blinking cursor in the Onda accent. Characters appear at a constant rate over duration frames, then the cursor — drawn in dusty rose so it earns one of the rare accent usages in the catalog — disappears once the line is fully typed. Body-font default (Space Grotesk) reads more "typed" than the display face.

Props

NameTypeDefaultNotes
textstring"motion graphics"What to type out. Multi-character so the reveal is visibly progressive.
delayinteger ≥ 00Frames before typing starts.
durationinteger ≥ 1DURATION.slow (24)Target frames to fully type the string. Gives the eye time to follow.
cursorbooleantrueWhether to render the blinking cursor while typing.
cursorColorstring"#D96B82"--onda-accent. The cursor is one of the few earned accent uses in the catalog.
colorstring"#F2F2F4"Text color — defaults to --onda-text.
fontSizenumber64Pixels. Wins over size if both are passed.
sizeSizeRole?Semantic typography role — 'hero' | 'heading' | 'subheading' | 'body' | 'caption'. Resolves to canvas-aware pixels via the smaller canvas dimension. fontSize wins when both are passed.
fontFamilystring'"Space Grotesk", sans-serif'The Onda body font — reads more "typed" than Clash Display. Never default to monospace system fonts.
fontWeightnumber500Font weight.
letterSpacingstring"normal"CSS letter-spacing.
lineHeightnumber1.4Unitless line height — looser for body / technical copy.
align"left" | "center" | "right""left"Text alignment.
placementPlacement?Where on the canvas this sits. Region ("center", "upper-third", …) or { x, y, anchor } in 0..1 canvas fractions. Coordinates may be negative or >1 for off-canvas.

Usage

TSX
import { Composition } from 'remotion';
import { Typewriter, typewriterSchema } from './components/onda/typewriter/Typewriter';

export const Root: React.FC = () => (
  <Composition
    id="MyTypewriter"
    component={Typewriter}
    durationInFrames={90}
    fps={30}
    width={1080}
    height={1920}
    schema={typewriterSchema}
    defaultProps={{
      text: 'motion graphics',
      delay: 0,
      duration: 24,
      cursor: true,
      cursorColor: '#D96B82',
      color: '#F2F2F4',
      fontSize: 64,
      fontFamily: '"Space Grotesk", sans-serif',
    }}
  />
);

Motion notes

  • Linear by design — the one intentional exception in the Onda catalog. Every other primitive uses SPRING_SMOOTH because springs feel premium. Typing is the opposite: a spring on charsToShow would land characters fast in the middle of the curve and slowly at the ends, breaking the constant-rate feel that makes typing read as typing. So progress here is a plain clamped interpolate from [0, duration] to [0, 1], and charsToShow = Math.floor(progress * text.length).
  • Accent cursor color. The cursor renders in --onda-accent (#D96B82). Color is earned in Onda, never sprinkled — a single dusty-rose bar moving across a neutral line is exactly the kind of restrained accent moment the brand calls for.
  • Deterministic blink. cursorVisible = Math.floor(frame / 15) % 2 === 0 toggles every 15 frames (0.5s at 30fps). It is a pure function of frame — no setInterval, no state — so any frame renders correctly in isolation, which is the Remotion contract.
  • Cursor lifecycle. The cursor <span> is always rendered (so the trailing layout is stable and the element can be styled by tooling), but its opacity drops to 0 once progress >= 1 or when cursor is false. While typing, opacity toggles between 1 and 0 on the blink cadence.
  • All interpolate calls clamp at both ends — the component is correct on frame 0 and on any frame past delay + duration.