Echo Reel

Rotating Text Headline for React

A giant word printed solid, with the words before and after it in the list stacked above and below as pale halftone proofs. Every few seconds the reel turns one row: the proof below rises into the middle while one roller pass moves the ink off the old word and onto the new one. Click a proof or press ↑ ↓ to turn it yourself, so it works as a headline that cycles who it's for or as a picker for plans.

  • Text
  • Hero
  • Motion

Uses clsx, tailwind-merge

Inspired by Cloudflare for Startups

Open in ChatGPTOpen in Claude
speed1.00×
<EchoReel />

The demo follows as you drag.

Cutline is made for creators, podcasters, studios and brands
Creators

One long recording in. Clips, captions and dubs for every channel out, cut while you sleep.

Take this demo to your coding agent.
Add this moment from KeyframeUI to our project and adapt it to our content.

Echo Reel: A giant word printed solid, with the words before and after it in the list stacked above and below as pale halftone proofs. Every few seconds the reel turns one row: the proof below rises into the middle while one roller pass moves the ink off the old word and onto the new one. Click a proof or press ↑ ↓ to turn it yourself, so it works as a headline that cycles who it's for or as a picker for plans.
This demo, Audiences: A video tool's hero that cycles who it's made for. It holds while you point at it and stops once you pick a word.

1. Install it:
   npx shadcn@latest add @keyframeui/echo-reel-demo
   (If the CLI can't find @keyframeui, use https://keyframeui.com/r/echo-reel-demo.json instead.)
   It adds the demo, components/echo-reel-demo.tsx, and the component, components/ui/echo-reel.tsx.

2. Make it ours: our copy, data, images and colors. Keep the structure the motion depends on. If we only need the effect, use <EchoReel> on its own.

3. These props set its feel. Change them before you change the file:
   - speed (default 1): How fast each turn plays, as a multiple of the default pace: the reel moving a row, the roller handing the ink over, the first print and the fades, together. `2` is twice as fast.

4. Don't change, in components/ui/echo-reel.tsx:
   - Rows move by `transform` and `opacity` only. The ink wipes by sliding its clipping window one way and the word inside it the other by the same amount, on one `rollTransition`, so the word never shifts.
   - Rows are keyed by absolute slot and the reel only turns the short way round, so each row keeps its element through a wrap; `reach` mounts enough rows that a jump never mounts one in view.
   - On a turn the roller trails the reel slightly on an in-out curve like the reel's, so the ink is handed over while the rows travel. `print` times only the first inking on view, before any turn.
   - Proof buttons are keyed by side, not by word, so focus stays put as the reel turns. A visitor's turn stops autoplay for good and is announced politely; autoplay turns are not.
   - Reduced motion swaps the rows at once and fades the new ink in over its proof, which drops only once that fade ends. The reduced flag reads false while hydrating, so the markup matches.
   Its timing is all in the TIMING block at the top of that file.

Docs: https://keyframeui.com/components/echo-reel.md

Installation

Add the component on its own with the CLI, or copy the file in by hand.

The CLI writes components/ui/echo-reel.tsx and installs clsx and tailwind-merge. It needs the @keyframeui registry in components.json; add it once per project.

npx shadcn@latest add @keyframeui/echo-reel

Examples

Finished sections built with Echo Reel. Each one installs whole, with the component included.

Plan Picker

The giant word picks a pricing plan: click the proof above or below, or use the arrow keys, and the price card beside it changes.

Tinta pricing

Click a plan above or below, or use ↑ ↓

Team
$36a month

For an in-house team keeping five brands in line.

  • Five brand kits, five seats
  • Shared templates and review links
  • Version history on every asset
Try Team free for 14 days
Take this demo to your coding agent.
Add this moment from KeyframeUI to our project and adapt it to our content.

Echo Reel: A giant word printed solid, with the words before and after it in the list stacked above and below as pale halftone proofs. Every few seconds the reel turns one row: the proof below rises into the middle while one roller pass moves the ink off the old word and onto the new one. Click a proof or press ↑ ↓ to turn it yourself, so it works as a headline that cycles who it's for or as a picker for plans.
This demo, Plan Picker: The giant word picks a pricing plan: click the proof above or below, or use the arrow keys, and the price card beside it changes.

1. Install it:
   npx shadcn@latest add @keyframeui/echo-reel-plans-demo
   (If the CLI can't find @keyframeui, use https://keyframeui.com/r/echo-reel-plans-demo.json instead.)
   It adds the demo, components/echo-reel-plans-demo.tsx, and the component, components/ui/echo-reel.tsx.

2. Make it ours: our copy, data, images and colors. Keep the structure the motion depends on. If we only need the effect, use <EchoReel> on its own.

3. These props set its feel. Change them before you change the file:
   - speed (default 1): How fast each turn plays, as a multiple of the default pace: the reel moving a row, the roller handing the ink over, the first print and the fades, together. `2` is twice as fast.

4. Don't change, in components/ui/echo-reel.tsx:
   - Rows move by `transform` and `opacity` only. The ink wipes by sliding its clipping window one way and the word inside it the other by the same amount, on one `rollTransition`, so the word never shifts.
   - Rows are keyed by absolute slot and the reel only turns the short way round, so each row keeps its element through a wrap; `reach` mounts enough rows that a jump never mounts one in view.
   - On a turn the roller trails the reel slightly on an in-out curve like the reel's, so the ink is handed over while the rows travel. `print` times only the first inking on view, before any turn.
   - Proof buttons are keyed by side, not by word, so focus stays put as the reel turns. A visitor's turn stops autoplay for good and is announced politely; autoplay turns are not.
   - Reduced motion swaps the rows at once and fades the new ink in over its proof, which drops only once that fade ends. The reduced flag reads false while hydrating, so the markup matches.
   Its timing is all in the TIMING block at the top of that file.

Docs: https://keyframeui.com/components/echo-reel.md

Props

words Required

Typestring[]

The words on the reel, in order. The next word waits below the current one and the previous one sits above. A single word prints a still stack of itself.

value

Typenumber

The index of the word in the middle, when the parent owns it. Pair it with onValueChange.

defaultValue

TypenumberDefault0

The index the reel starts on when it runs by itself.

onValueChange

Type(index: number, reason: "auto" | "user") => void

Called with the new index each time the reel turns, and whether autoplay or the visitor turned it.

interval

Typenumber | falseDefault3

Seconds between turns by itself, or false to wait for the visitor. Hover and focus hold it, and the visitor's first turn stops it.

speed

TypenumberDefault1

How fast each turn plays, as a multiple of the default pace: the reel moving a row, the roller handing the ink over, the first print and the fades, together. 2 is twice as fast.

echoes

Type1 | 2Default1

How many proofs sit on each side of the word.

className

Typestring

Extra classes for the reel. Its text color is the ink; set --echo-reel-tint for the proofs (default the ink at 38%) and --echo-reel-dot for the halftone pitch (default clamp(4px, 0.028em, 8px)). The longest word is sized to fill the width, so size the reel with its container.