G13▸V105▸gsap
Animated Beam
流動光束連線
難度 ★★★★★標籤 svg · path · beam · connection3 min read
效果簡述
兩個元素之間用 SVG 曲線連起來,光點沿著線跑。Magic UI 的
animated-beam 招式。展示「資料流」、「整合」、「同步」概念神器。
API
DB
Claude Code Prompt
參考:V105 animated beam
技術:SVG path + getPointAtLength + gsap repeat -1
具體行為:
- 線本身用 strokeDasharray + strokeDashoffset 入場畫出來
- 用 gsap.to({ p: 0 }, { p: 1, repeat: -1, onUpdate: () => { const pt = path.getPointAtLength(p * len); dot.setAttribute('cx', pt.x); dot.setAttribute('cy', pt.y) } })
- 光點用 circle,dot 也可疊發光 filter (Gaussian blur)
限制:
- path 要平滑(Bezier C / Q)
- 不要超過 5 條同時跑(畫面亂)
- 響應式時 path d 要重算(用 viewBox 撐起來,內部座標不變)完整程式碼
'use client'
import gsap from 'gsap'
import { useEffect, useRef } from 'react'
export function AnimatedBeam() {
const pathRef = useRef<SVGPathElement>(null)
const dotRef = useRef<SVGCircleElement>(null)
useEffect(() => {
const path = pathRef.current
const dot = dotRef.current
if (!path || !dot) return
const len = path.getTotalLength()
gsap.set(path, { strokeDasharray: len, strokeDashoffset: len })
gsap.to(path, { strokeDashoffset: 0, duration: 1.4 })
const tl = gsap.to({ p: 0 }, {
p: 1, duration: 2.2, ease: 'none', repeat: -1, delay: 1.2,
onUpdate() {
const pt = path.getPointAtLength(this.targets()[0].p * len)
dot.setAttribute('cx', String(pt.x))
dot.setAttribute('cy', String(pt.y))
},
})
return () => tl.kill()
}, [])
return (
<svg viewBox="0 0 400 170">
<path ref={pathRef} d="M 60 85 C 140 30, 260 140, 340 85" fill="none" stroke="currentColor" />
<circle ref={dotRef} r="5" fill="currentColor" />
</svg>
)
}何時用
- ✅ 整合 / API 連接示意(A → B 連線)
- ✅ 架構圖視覺化
- ✅ 「資料流動」概念展示
何時別用
- ❌ 簡單裝飾(殺雞用牛刀,CSS 動畫就夠)
- ❌ 連線意義不明(觀眾迷惑)
- ❌ 條數太多(畫面雜亂)
我踩過的坑
-
getPointAtLength 是同步但有 cost:path 數量多時每幀算多個點 會慢。一頁不要超過 5 條 beam。
-
gsap.to 的 onUpdate this:
this.targets()[0]拿到 proxy 物件, 不是直接this.target。 -
響應式 path d 要小心:viewBox 跟內部座標不變的話 SVG 自動縮放 ok。但若用 px 寫 path d 響應式會破。
相關效果
- G06 SVG Path Draw — 純 path 畫
- G07 Logo Reveal — 多 path 串接