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.

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>
);
Props
PropTypeDefaultDescription
captions
Caption[]—The timed transcript, in the `Caption` shape from `@remotion/captions`. Times are relative to the start of the surrounding `Sequence`.
width
number1100Width of the visible strip in composition pixels.
pxPerSecond
number260How far apart one second of speech is on the strip — also the scroll speed during pauses.
playheadPosition
number0.35Where the playhead sits across the strip, from 0 (left edge) to 1 (right edge).
playheadColor
string"#facc15"Colour of the playhead line.
upcomingOpacity
number0.4Opacity of words the playhead has not reached yet.
fontSize
number64Font size in pixels.
fontWeight
number800Font weight. The font itself is inherited.
color
string"#ffffff"Text colour.
shadow
booleantrueA 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`.