Audio player

A player for a generated track or voice clip, with a waveform you can scrub, playback speed and download.

Loading preview…

Install

  1. 1

    Run this command in your Tailwind CSS project. It adds components/ai/audio-player.tsx and installs its dependencies.

    $ npx shadcn@latest add https://gradientdeck.com/ai-components/r/audio-player.json

Usage & API

Example

audio-player.tsx
import { AudioPlayer } from "@/components/ai/audio-player"

<AudioPlayer
  title="…"
  duration={1}
  time={1}
  onTimeChange={() => {}}
  playing={true}
  onPlayingChange={() => {}}
  speed={1}
  onSpeedChange={() => {}}
/>

Props AudioPlayer

PropType & descriptionRequired
titlestringRequired
subtitlestringOptional
durationnumberSecondsRequired
timenumberSecondsRequired
onTimeChange(time: number) => voidRequired
playingbooleanRequired
onPlayingChange(playing: boolean) => voidRequired
speednumberRequired
onSpeedChange(speed: number) => voidRequired
onDownload() => voidOptional
seednumberSeed for the waveform shape.Optional
barsnumberOptional

Dependencies

  • React
  • Tailwind CSS
  • motion
  • lucide-react
Implementation notes

Waveform is the only variant. The seek surface is a slider labelled Seek, with a value text of the current clock against the duration, formatted as minutes and seconds. Pointer down seeks immediately and continues while dragging. The playhead is visual only. The bars are the hit target. Skip buttons are labelled Back 5 seconds and Forward 5 seconds and clamp to the ends. The centre button is labelled Pause or Play. Speed is a pill that shows the number and a times sign. Download sits opposite the clock so the transport stays centred. The cover spin is a nine-second linear loop and only runs while playing. Reduced motion stops that rotation. The demo's clock follows speed, pauses itself at the end, and does not load an audio element either.

Choosing a layout

Use it when the model returned audio and the person needs to hear it, skim it, change speed, and take the file. A spoken summary, a voice take, or a short piece of music all match the speech-shaped bars better than a thin progress line. Because the waveform is seeded rather than decoded, you can render the player before you have analysed peaks, or keep the same shape across replays. If you later want real peaks, this file does not accept a peak array. The shape is internal.

Use Video generation when the result is frames and a picture that plays, not a waveform. The two cards solve different waits: video shows a strip filling in, and this player assumes the clip is already something you can seek. Do not use it as a live meter while someone is talking. This player has a duration and a playhead because the audio is a finished clip, not an open session. If all you need is a native audio element with browser chrome, you do not need this card.

Does the waveform come from the audio file?

No. Bar heights are a function of seed and the bar count, shaped to look like speech. Duration and time are separate props and only drive how many bars count as played. Two clips with the same seed will share a silhouette even when their audio differs.

Which playback speeds are available?

The button walks a fixed cycle: 1, 1.25, 1.5, 2, and 0.75, then back to 1. It calls onSpeedChange with the next value. It does not accept an arbitrary rate, and it does not apply the rate to time. Whatever plays the audio should use the speed you store.