Mischief

63 / Agent UI

Transcript Viewer

A recording as text, where every line is also the way back to the moment it was said.

0:14
0:44

Installation

Copy the source into your project, or keep it behind a package.

npx shadcn@latest add Tinkerers-Labs/mischief-ui/transcript-viewer
import { TranscriptViewer } from "mischief-ui/transcript-viewer"

Or paste it in yourself. The source imports the shared cn helper from @/lib/utils, so point that at your own copy.

registry/default/transcript-viewer/transcript-viewer.tsx
"use client" import * as React from "react" import { cn } from "@/lib/utils" export type TranscriptCue = {  id: string  /** Seconds from the start of the recording. */  start: number  end?: number  speaker?: string  text: string}

Usage

export function Recording() {
  return (
    <TranscriptViewer
      cues={cues}
      time={time}
      onSeek={(cue) => player.seek(cue.start)}
    />
  )
}

Reading and scrubbing are one act

Give it the position and it marks the line being spoken; click a line and it hands you the second to seek to. Neither is a separate mode, which is the whole point: people look for a sentence they remember, not for a timestamp they never knew.

A cue with no end is treated as running until the next one begins, so a transcript from a service that only reports start times needs no preparation.

Following without hijacking

While it follows, the active line is scrolled into view by the nearest amount that puts it on screen, never centred. Centring on every cue drags the page under a reader who was looking at something else a moment ago.

API

cuesTranscriptCue[]The transcript, in order.
timenumberWhere the recording is now, in seconds.
onSeek(cue: TranscriptCue) => voidA line was chosen.
followbooleanScrolls to the active line. On by default.
labelstringNames the list. Defaults to "Transcript".

TranscriptCue

idstringDistinct within the transcript.
startnumberSeconds from the beginning.
endnumberOptional. Defaults to the next cue's start.
speakerstringShown before the line.
textstringWhat was said.

Accessibility

Every line is a real button, so the transcript is operable from the keyboard without any arrow-key handling of its own, and the line being spoken carries aria-current rather than only a background colour. Times are rendered in minutes and seconds instead of as a raw number of seconds, which is what a screen reader would otherwise read aloud.