# Word Stream
URL: https://remocn.dev/docs/typography/word-stream

Voiceover-paced phrases building word by word while the line drifts left

- Install: `npx shadcn@latest add @remocn/word-stream`
- Vibe: premium
- Natural length: 63f @ 30fps

## Installation

```bash
npx shadcn@latest add @remocn/word-stream
```

## Usage

Phrases are passed as a single string separated by `|`. Each phrase glides in decelerating, builds word by word while slowly drifting left, then accelerates out to the left and hard-cuts to the next phrase. The last phrase stays on screen.

```tsx
// src/Root.tsx
import { Composition } from "remotion";
import { WordStream } from "@/components/remocn/word-stream";

const WordStreamScene = () => (
  <WordStream text="introducing | one-tap checkout | for your store" />
);

export const RemotionRoot = () => (
  <Composition
    id="WordStream"
    component={WordStreamScene}
    durationInFrames={100}
    fps={30}
    width={1280}
    height={720}
  />
);
```

### With Backdrop

The component renders transparent — supply the background via `Backdrop`. It ships single-theme; edit the copied file to re-theme colors.

```tsx
import { Composition } from "remotion";
import { WordStream } from "@/components/remocn/word-stream";
import { Backdrop } from "@/components/remocn/backdrop";

const WordStreamScene = () => (
  <Backdrop fill={{ type: "color", value: "#0b0b14" }}>
    <WordStream
      text="introducing | one-tap checkout | for your store"
      color="#ffffff"
    />
  </Backdrop>
);

export const RemotionRoot = () => (
  <Composition
    id="WordStream"
    component={WordStreamScene}
    durationInFrames={100}
    fps={30}
    width={1280}
    height={720}
  />
);
```

### Syncing to a voiceover

`wordGap` is the number of frames between word reveals — match it to the speaking pace of the narration (at 30fps, `wordGap={6}` is 5 words per second). `hold` controls how long a finished phrase stays before the next one starts. The exported `wordStreamLength(text, wordGap, hold)` helper returns the frame on which the last word finishes resolving — use it as the lower bound of the `Sequence`.

## Props

| Prop | Type | Default | Description |
|---|---|---|---|
| `text` (required) | `string` | — | Phrases separated by \|. Words within a phrase are split on spaces. |
| `fontSize` | `number` | `72` | Font size in pixels |
| `wordGap` | `number` | `6` | Frames between consecutive word reveals |
| `hold` | `number` | `18` | Frames a completed phrase holds before swapping to the next |
| `drift` | `number` | `2` | Leftward crawl of the line in pixels per frame between the entry glide and the exit run-out (at fontSize 72, scales proportionally). 0 disables the crawl. |
| `color` | `string` | `"#171717"` | Text color (any valid CSS color) |
| `fontWeight` | `number` | `400` | CSS font-weight |
| `className` | `string` | — | Optional className passed to the underlying span |

## Use when
- An intro or narration follows a voiceover and each phrase should build word by word at speaking pace.
- You want the keynote-style restless motion where the whole line keeps drifting left as new words pop in on the right.
- Several short phrases need to play in sequence inside a single component, with fast cut-like swaps between them.

## Don't use when
- There is only one static phrase to reveal — use `per-word-crossfade` for a single calm word-by-word entrance.
- You need a two-state before/after text swap rather than a stream — use `value-swap` or `strikethrough-replace`.
- The text is a multi-line paragraph — use `line-by-line-slide` or `mask-reveal-up` for line-level reveals.
- The words follow a real voiceover — use `caption-karaoke` or another style from the Captions tab, which times every word from a transcript instead of inventing the pace.