Timeline

The whole transcript laid out on a scrolling time strip that slides under a fixed playhead, so every pause shows up as space between words

Installation
$ pnpm dlx shadcn@latest add @remocn/caption-timeline

Usage

CaptionTimeline places every word of the transcript on a horizontal strip at a position proportional to when it is spoken, pxPerSecond apart, and scrolls the strip so the current moment sits under a fixed playhead. A pause in the speech becomes empty space on the strip; when words come faster than the strip can fit them, they are pushed apart so they never overlap. Words ahead of the playhead are dimmed to upcomingOpacity and light up as the playhead reaches them, and both ends of the strip fade out.

The strip is not paged, so combineTokensWithinMilliseconds and holdMs have no effect, and it stays on screen for the whole transcript. Give it a fixed width in composition pixels and place it yourself — see Positioning and Get a transcript.

tsx
import { AbsoluteFill } from "remotion";
import { CaptionTimeline } from "@/components/remocn/caption-timeline";
import captions from "./captions.json";
 
export const MyScene = () => (
  <AbsoluteFill
    style={{
      justifyContent: "flex-end",
      alignItems: "center",
      paddingBottom: 108,
    }}
  >
    <CaptionTimeline captions={captions} width={1600} />
  </AbsoluteFill>
);

Props13

PropTypeDefault
captions
Caption[]—

The timed transcript, in the `Caption` shape from `@remotion/captions`. Times are relative to the start of the surrounding `Sequence`.

width
number1100

Width of the visible strip in composition pixels.

pxPerSecond
number260

How far apart one second of speech is on the strip — also the scroll speed during pauses.

playheadPosition
number0.35

Where the playhead sits across the strip, from 0 (left edge) to 1 (right edge).

playheadColor
string"#facc15"

Colour of the playhead line.

upcomingOpacity
number0.4

Opacity of words the playhead has not reached yet.

fontSize
number64

Font size in pixels.

fontWeight
number800

Font weight. The font itself is inherited.

color
string"#ffffff"

Text colour.

shadow
booleantrue

A tight text shadow that keeps the caption legible over bright footage.

combineTokensWithinMilliseconds
number—

Accepted for API parity with other caption styles; unused, since the strip is not paged.

holdMs
number—

Accepted for API parity with other caption styles; unused, since the strip never leaves the screen.

className
string—

Classes for the strip — font family, `uppercase`.

  • captionsCaption[]

    The timed transcript, in the `Caption` shape from `@remotion/captions`. Times are relative to the start of the surrounding `Sequence`.

    Default—

  • widthnumber

    Width of the visible strip in composition pixels.

    Default1100

  • pxPerSecondnumber

    How far apart one second of speech is on the strip — also the scroll speed during pauses.

    Default260

  • playheadPositionnumber

    Where the playhead sits across the strip, from 0 (left edge) to 1 (right edge).

    Default0.35

  • playheadColorstring

    Colour of the playhead line.

    Default"#facc15"

  • upcomingOpacitynumber

    Opacity of words the playhead has not reached yet.

    Default0.4

  • fontSizenumber

    Font size in pixels.

    Default64

  • fontWeightnumber

    Font weight. The font itself is inherited.

    Default800

  • colorstring

    Text colour.

    Default"#ffffff"

  • shadowboolean

    A tight text shadow that keeps the caption legible over bright footage.

    Defaulttrue

  • combineTokensWithinMillisecondsnumber

    Accepted for API parity with other caption styles; unused, since the strip is not paged.

    Default—

  • holdMsnumber

    Accepted for API parity with other caption styles; unused, since the strip never leaves the screen.

    Default—

  • classNamestring

    Classes for the strip — font family, `uppercase`.

    Default—