Animated Beam
節點間流動光束,適合整合示意圖與資料流動畫。
在任意兩個節點之間繪製一條會流動的光束,路徑隨容器尺寸自動重算,最適合畫整合示意圖、資料管線與架構圖。
把這個效果裝進你的專案
在專案資料夾執行指令,CLI 會加入原始碼與依賴套件,再依下方使用範例引用元件。
npx webberui@latest add animated-beamAnimated Beam 是用 React、SVG 與 Motion(motion/react)做的動態連線光束(animated beam/流程連接線)元件:依兩個節點的實際位置畫出直線或二次貝茲曲線,再讓一段漸層亮光沿線流動。常用來畫整合架構圖、資料流向或「多個來源匯入一個平台」的示意圖。
Playground
即時調整 props、程式碼片段同步更新——直接試出你要的樣子再複製。
<AnimatedBeam/>
完整範例包含預覽的排版與資料。先安裝元件,再把範例檔貼入你的專案。
適用情境
- SaaS 首頁的整合區塊:多個第三方服務連到你的產品 logo
- 說明資料流向的架構圖,例如「使用者、API、資料庫」
- 開發者工具介紹同步、部署流程,用反向光束表示雙向傳輸
- 產品功能頁的「運作方式」示意區
- 不適合:要表達有先後順序、帶文字說明的流程步驟時,改用 Orbit Timeline 或 Stepper 這類有標籤的元件
安裝
npx webberui@latest add https://webberui.com/r/animated-beam.json或在 components.json 設定 registries 後,改用 @webberui/animated-beam 安裝。
使用
光束是一個絕對定位的疊層,透過三個 ref 量測座標:containerRef 是量測原點,fromRef / toRef 是兩端節點。把節點與光束都放進同一個 relative 容器即可。
"use client";
import * as React from "react";
import { AnimatedBeam } from "@/components/ui/animated-beam";
export function Diagram() {
const containerRef = React.useRef<HTMLDivElement>(null);
const fromRef = React.useRef<HTMLDivElement>(null);
const toRef = React.useRef<HTMLDivElement>(null);
return (
<div ref={containerRef} className="relative flex justify-between p-10">
<div ref={fromRef} className="size-11 rounded-full bg-white" />
<div ref={toRef} className="size-11 rounded-full bg-white" />
<AnimatedBeam
containerRef={containerRef}
fromRef={fromRef}
toRef={toRef}
/>
</div>
);
}節點需要有實際尺寸與定位;光束以 -z-10 疊在節點之下,請確保容器帶 relative。多條光束用不同的 delay 錯開流動時序,用 curvature 讓匯聚到同一樞紐的線條散開。
範例
多個來源匯入同一個樞紐
左側每個節點各接一條光束到中央節點。用不同的 curvature 讓線條散開,用 delay 錯開流動時間。
"use client";
import * as React from "react";
import { AnimatedBeam } from "@/components/ui/animated-beam";
const sources = ["表單", "金流", "客服"];
export function IntegrationDiagram() {
const containerRef = React.useRef<HTMLDivElement>(null);
const hubRef = React.useRef<HTMLDivElement>(null);
const sourceRefs = [
React.useRef<HTMLDivElement>(null),
React.useRef<HTMLDivElement>(null),
React.useRef<HTMLDivElement>(null),
];
return (
<div ref={containerRef} className="relative isolate flex items-center justify-between p-10">
<div className="flex flex-col gap-8">
{sources.map((label, i) => (
<div key={label} ref={sourceRefs[i]} className="rounded-lg border bg-white px-3 py-2 text-sm">
{label}
</div>
))}
</div>
<div ref={hubRef} className="size-14 rounded-full border bg-white" />
{sourceRefs.map((ref, i) => (
<AnimatedBeam
key={i}
containerRef={containerRef}
fromRef={ref}
toRef={hubRef}
curvature={(1 - i) * 40}
delay={i * 0.4}
/>
))}
</div>
);
}雙向傳輸
兩個節點之間放兩條光束:一條正向、一條 reverse,並用 Y 偏移把線拉開,避免重疊。
<AnimatedBeam
containerRef={containerRef}
fromRef={appRef}
toRef={serverRef}
startYOffset={-8}
endYOffset={-8}
curvature={20}
/>
<AnimatedBeam
containerRef={containerRef}
fromRef={appRef}
toRef={serverRef}
startYOffset={8}
endYOffset={8}
curvature={-20}
reverse
/>自訂顏色與線寬
gradientStartColor、gradientStopColor 控制流動亮光的漸層,pathColor 與 pathOpacity 控制底下的靜態軌道。
<AnimatedBeam
containerRef={containerRef}
fromRef={fromRef}
toRef={toRef}
pathWidth={3}
pathColor="#a3a3a3"
pathOpacity={0.3}
gradientStartColor="#f97316"
gradientStopColor="#facc15"
duration={4}
/>Props
| Prop | 型別 | 預設值 | 說明 |
|---|---|---|---|
containerRef | RefObject<HTMLElement | null> | — | 量測座標用的外層容器 |
fromRef | RefObject<HTMLElement | null> | — | 光束起點節點 |
toRef | RefObject<HTMLElement | null> | — | 光束終點節點 |
curvature | number | 0 | 曲率(px):正值上拱、負值下沉 |
reverse | boolean | false | 反向流動(終點朝起點) |
duration | number | 3 | 單次流動時長(秒) |
delay | number | 0 | 進場前延遲(秒) |
pathColor | string | "currentColor" | 靜態底線顏色 |
pathWidth | number | 2 | 線寬(px) |
pathOpacity | number | 0.15 | 底線透明度 |
gradientStartColor | string | "#818cf8" | 流動漸層起點色 |
gradientStopColor | string | "#22d3ee" | 流動漸層終點色 |
startXOffset | number | 0 | 起點 X 微調(px) |
startYOffset | number | 0 | 起點 Y 微調(px) |
endXOffset | number | 0 | 終點 X 微調(px) |
endYOffset | number | 0 | 終點 Y 微調(px) |
可及性
- 使用者系統開啟「減少動態效果」時,只保留靜態底線、不播放流動亮點
- 光束層帶
aria-hidden,純裝飾不干擾輔助科技 - 路徑透過
ResizeObserver監聽容器尺寸變化,RWD 下自動重算,離開時清理
常見問題
可以在 Next.js App Router 使用嗎?
可以。檔案開頭已有 "use client",但因為要建立 ref,包住節點與光束的那個元件也要是用戶端元件,如上方範例開頭的 "use client"。路徑在 effect 裡量測,伺服器端渲染時是空路徑。
為什麼看不到光束?
先確認容器有 relative,節點有實際尺寸。光束以 -z-10 疊在節點下方,如果容器本身有背景色,光束可能被蓋住;在容器加上 isolate 建立新的堆疊脈絡即可。
版面改變時路徑會更新嗎?
容器尺寸改變時會透過 ResizeObserver 重算。只監看容器,若節點自己移動但容器尺寸不變(例如節點本身有位移動畫),路徑不會跟著更新。
支援減少動態效果嗎?
支援。系統開啟「減少動態效果」時,只顯示靜態底線,不播放流動亮光。整個 SVG 帶 aria-hidden,不會被螢幕閱讀器讀到。
需要哪些依賴?
motion、clsx 與 tailwind-merge。也可以從安裝區塊的「手動」分頁複製原始碼。