Skip to content

pastetaste

Ribbon Sentence

TextHeroesAnimation

A title told word by word on giant curving colour ribbons, then the camera pulls back and the ribbons straighten into one line of colour-blocked words that stays on the page.

Paste it into Claude Code: it installs the component, asks for your brand and content, and places it on the page you name.

Install

Or by hand, in a Next.js project with shadcn set up. It writes components/pastetaste/ribbon-sentence.tsx.

npx shadcn@latest add https://pastetaste.com/r/ribbon-sentence.json

Prompt

Install the pastetaste component "Ribbon Sentence" (ribbon-sentence) into this Next.js project and use it.

What it is: A title told word by word on giant curving colour ribbons, then the camera pulls back and the ribbons straighten into one line of colour-blocked words that stays on the page.

Before you place it, ask me (one short message, in my language; "skip" = sensible default): which page and section it goes in, my brand colour (hex), the text, labels or images it should show, and whether I want my logo or my own copy in the demo content. Then:

Steps:
1. If the project has no components.json, run: npx shadcn@latest init -y -d. Then run: npx shadcn@latest add https://pastetaste.com/r/ribbon-sentence.json
   (it writes components/pastetaste/ribbon-sentence.tsx; install any npm packages it reports).
2. Import it: import { RibbonSentence } from "@/components/pastetaste/ribbon-sentence" (check the file for the exact named export).
3. Put it where it fits on the page I name, keep the rest of the page untouched, and pass props for my colours instead of editing the installed file.
4. It does not depend on Tailwind; colours come from CSS variables (--pt-*) or props.
5. It supports prefers-reduced-motion with a still state; do not remove it.

Props (all optional unless the type has no default):
- words: string | (string | { text, color?, ink? })[] = required — The sentence. A string is split on spaces; an array gives one block per entry and lets a word set its own colour and ink.
- palette: { color: string; ink: string }[] = RIBBON_PALETTE — Block and text colours handed to the words in order, cycled for longer sentences. The default is ink, signal red, lilac, yellow and violet.
- as: 'h1' | 'h2' | 'h3' | 'p' | 'div' = 'h2' — Tag of the resting line, which is real, selectable text.
- size: string = 'clamp(20px, 4.4cqi, 60px)' — Font size of the resting line, any CSS length (cqi is the stage width). The close-up scales from the stage size.
- children: ReactNode — Shown under the line once it has landed, e.g. a caption or a button. It fades up after the ribbons settle.
- trigger: 'view' | 'mount' = 'view' — Start when the stage is 30% on screen, or as soon as it mounts. Read once on mount.
- wordDuration: number = 0.36 — Seconds the camera spends on each word in close-up.
- gatherDuration: number = 0.85 — Seconds of the pull-back from ribbons to the line.
- delay: number = 0.15 — Seconds before the first word moves.
- loop / hold: boolean / number = false / 2.6 — Play again after hold seconds at rest, only while the stage is on screen.
- playKey: string | number — Change it to replay, e.g. from a Replay button.
- scramble: boolean = true — Before a replay or loop the blocks shuffle colours and widths for a beat, then the stage cuts back to the close-up.
- onStart / onComplete: () => void — Called when the close-up starts and when the line has landed (at once under reduced motion).
- className / style: string / CSSProperties — On the stage. The stage is 100% of its parent's height with a 320px minimum; give the parent a height.

Live preview: https://pastetaste.com/c/ribbon-sentence
Then run the dev server, check it in the browser at desktop and mobile width, and tell me the page URL.

Props 14

PropTypeDefaultDescription
wordsstring | (string | { text, color?, ink? })[]requiredThe sentence. A string is split on spaces; an array gives one block per entry and lets a word set its own colour and ink.
palette{ color: string; ink: string }[]RIBBON_PALETTEBlock and text colours handed to the words in order, cycled for longer sentences. The default is ink, signal red, lilac, yellow and violet.
as'h1' | 'h2' | 'h3' | 'p' | 'div''h2'Tag of the resting line, which is real, selectable text.
sizestring'clamp(20px, 4.4cqi, 60px)'Font size of the resting line, any CSS length (cqi is the stage width). The close-up scales from the stage size.
childrenReactNode-Shown under the line once it has landed, e.g. a caption or a button. It fades up after the ribbons settle.
trigger'view' | 'mount''view'Start when the stage is 30% on screen, or as soon as it mounts. Read once on mount.
wordDurationnumber0.36Seconds the camera spends on each word in close-up.
gatherDurationnumber0.85Seconds of the pull-back from ribbons to the line.
delaynumber0.15Seconds before the first word moves.
loop / holdboolean / numberfalse / 2.6Play again after hold seconds at rest, only while the stage is on screen.
playKeystring | number-Change it to replay, e.g. from a Replay button.
scramblebooleantrueBefore a replay or loop the blocks shuffle colours and widths for a beat, then the stage cuts back to the close-up.
onStart / onComplete() => void-Called when the close-up starts and when the line has landed (at once under reduced motion).
className / stylestring / CSSProperties-On the stage. The stage is 100% of its parent's height with a 320px minimum; give the parent a height.
View all →