文字動畫

Scramble Text

亂碼快速輪轉、由左至右逐字定型的解密文字動畫,支援視口與 hover 觸發。

把這個效果裝進你的專案

在專案資料夾執行指令,CLI 會加入原始碼與依賴套件,再依下方使用範例引用元件。

npx webberui@latest add scramble-text

還沒有專案,或安裝遇到問題?看快速開始 →

Playground

即時調整 props、程式碼片段同步更新——直接試出你要的樣子再複製。

0.05
編輯中的呼叫預設屬性
<ScrambleText/>

完整範例包含預覽的排版與資料。先安裝元件,再把範例檔貼入你的專案。

安裝

npx webberui@latest add https://webberui.com/r/scramble-text.json

或在 components.json 設定 registries 後,改用 @webberui/scramble-text 安裝。

使用

import { ScrambleText } from "@/components/ui/scramble-text";

<ScrambleText
  text="WEBBERUI DECRYPTED"
  className="font-mono text-4xl font-bold"
/>

hover 重播模式,中英混合也沒問題:

<ScrambleText text="Hover 我:解密動畫" trigger="hover" duration={0.04} />

自訂亂碼字元集(例如駭客風的 0 和 1):

<ScrambleText text="BINARY MODE" charset="01" className="font-mono" />

首屏就是亂碼(SSR 安全),文字更新時讓讀屏播報真文字:

<ScrambleText text={status} initialScrambled live="polite" />

Props

Prop型別預設值說明
textstring—目標文字,中文與 emoji 皆可
durationnumber0.05每個字元定型的間隔(秒),越小解密越快
charsetstring英數+符號亂碼輪轉使用的字元集
trigger"view" | "hover""view"進入視口自動播放,或滑鼠懸停時重播
oncebooleantruetrigger="view" 時,只在第一次進入視口播放
initialScrambledbooleanfalse首次渲染(含 SSR)就顯示確定性 hash 亂碼而非答案,伺服器與瀏覽器輸出一致
live"off" | "polite" | "assertive""off"讀屏用真文字的 aria-live 等級;off 不加 aria-live

細節

  • 核心是單一 requestAnimationFrame 迴圈:依經過時間計算已定型的字元數(由左至右每 duration 秒多鎖定一個),未定型位置每 2 幀從 charset 抽一個新亂碼,避免逐幀閃爍太刺眼。動畫直接寫入 DOM 文字節點,不觸發 React re-render;unmount 或重播時都會取消前一個 rAF
  • 以 Intl.Segmenter 做字素切割,中文、emoji、組合字都算一個單位;定型時直接鎖定原始字元,所以中文目標文字一樣正常運作,亂碼輪轉則一律使用 charset
  • 空白字元不參與亂碼,行寬與斷行在動畫過程中保持穩定
  • 字寬抖動:亂碼輪轉時各字元寬度不同,畫面會左右跳動。建議搭配 font-mono(等寬字型),或至少在數字為主的場景加上 tabular-nums;目標文字含中文時,中英字寬差異讓抖動更明顯,等寬字型效果最好
  • 可及性:完整文字放在 sr-only,動畫層標記 aria-hidden,螢幕閱讀器永遠讀到完整句子而不是亂碼;使用者系統開啟「減少動態效果」時直接顯示最終文字,不播動畫
  • initialScrambled:預設首次渲染輸出的是答案本身(trigger="view" 時以透明度隱藏到進入視口)。開啟後首次渲染改輸出亂碼,亂碼由「字素內容+位置」算 FNV-1a hash 對應到 charset,不用 Math.random,所以伺服器與瀏覽器產生同一串字、不會 hydration 不一致;首屏已是亂碼、不會洩漏答案,因此 view 模式也不再先隱藏。搭配 trigger="hover" 時文字會維持亂碼直到第一次滑鼠移入
  • live:真文字放在 sr-only 層,live="polite" 或 "assertive" 會在該層加上 aria-live,text 變更時讀屏只播報一次完整的新文字,亂碼層維持 aria-hidden 不會被念出
  • once={false} 搭配 trigger="view" 時,離開視口再進入會重播;trigger="hover" 則是靜態顯示文字,每次滑鼠移入都重新解密一次