3D Rolling Text
滾動驅動的 3D 圓柱文字,行句貼在隱形滾筒上,隨捲動依序翻轉到正面。
載入預覽⋯
Playground
即時調整 props、程式碼片段同步更新——直接試出你要的樣子再複製。
160
56
900
6
<3dRollingText />
安裝
npx shadcn@latest add https://webberui.com/r/3d-rolling-text.json或在 components.json 設定 registries 後,改用 @webberui/3d-rolling-text 安裝。
安裝依賴後,從 registry JSON(/r/3d-rolling-text.json 的 files[0].content)複製 3d-rolling-text.tsx 原始碼到你的 components/ui/ 目錄:
npm install motion clsx tailwind-merge使用
import { RollingText3D } from "@/components/ui/3d-rolling-text";
<RollingText3D
lines={["Design", "Animate", "Prototype", "Ship"]}
lineClassName="text-5xl font-bold tracking-tight"
/>元件本身是一段可捲動的軌道(總高 = stageHeight + (行數 - 1) * stepHeight),內部以 sticky 舞台固定畫面。放進頁面後,捲過這段軌道即完成一整輪滾筒動畫。
巢狀捲動容器
若動畫發生在 overflow-y: auto 的容器內(而非整頁捲動),把容器的 ref 傳給 container:
const scrollerRef = React.useRef<HTMLDivElement>(null);
<div ref={scrollerRef} className="h-[300px] overflow-y-auto">
<RollingText3D lines={words} container={scrollerRef} />
</div>Props
| Prop | 型別 | 預設值 | 說明 |
|---|---|---|---|
lines | string[] | — | 圓柱面上的文字行,隨滾動依序翻轉到正面 |
stepHeight | number | 160 | 每一行對應的滾動距離(px),越大轉得越慢 |
stageHeight | number | 200 | 吸附舞台(sticky 視窗)的高度(px) |
lineHeight | number | 56 | 行高(px),同時決定圓柱半徑 |
perspective | number | 900 | 3D 透視距離(px),越小透視越誇張 |
direction | "up" | "down" | "up" | up 表示新行由下往上滾入正面,down 則由上往下 |
minFaces | number | 6 | 圓柱最少切分的面數;行數少時仍保持滾筒的弧度 |
container | React.RefObject<HTMLElement | null> | — | 巢狀捲動容器的 ref;預設以視窗為捲動容器 |
className | string | — | 套用在整段滾動軌道上的 class |
lineClassName | string | — | 套用在每一行文字上的 class(字級、字重、顏色) |
細節
- 圓柱幾何:半徑由
lineHeight / 2 / tan(π / faces)推得,讓相鄰兩面在滾筒上剛好相接,翻轉時不留縫也不重疊 - 捲動映射:
useScroll取軌道進度,走完全程剛好讓最後一行轉到正面((行數 - 1) × 每面角度),中途停住就停在對應角度,可倒轉 - 角距淡出:每一行依「與正面的角距」計算透明度——正面全亮、相鄰面半透明、更遠即消失,同時以
backface-visibility: hidden保底,避免鏡像字 - 行數少時:以
minFaces保底切面數,三、四行也能維持滾筒的弧度而不會退化成攤平的翻頁
可及性
- 使用者系統開啟「減少動態效果」時,放棄 3D 與 sticky,改以靜態直列渲染全部行句
- 完整文字以
sr-only提供給輔助科技,3D 視覺層整體aria-hidden,朗讀時是連續完整的內容 - 純捲動驅動、無自動播放:動畫進度完全跟隨使用者的捲動操作,隨時可停可倒轉