動畫數學
深入理解 interpolate 的映射原理與進階動畫技巧。
interpolate 的本質
interpolate() 本質上是一個值映射函數。它把一個範圍的數值映射到另一個範圍:
輸入範圍: [0, 30] → 輸出範圍: [0, 1]
frame = 0 → 0
frame = 15 → 0.5
frame = 30 → 1
多段映射
interpolate 可以定義多個關鍵幀,實現分段動畫:
const opacity = interpolate(
frame,
[0, 20, 70, 90], // 輸入:4 個時間點
[0, 1, 1, 0], // 輸出:4 個對應值
{ extrapolateLeft: "clamp", extrapolateRight: "clamp" }
);
// 0→20 幀:淡入(0→1)
// 20→70 幀:停留(1→1)
// 70→90 幀:淡出(1→0)這個模式非常常用——淡入 → 停留 → 淡出。
Easing 函數
預設的 interpolate 是線性的。用 easing 參數加入緩動效果:
import { interpolate, Easing } from "remotion";
const value = interpolate(frame, [0, 30], [0, 1], {
easing: Easing.bezier(0.25, 0.1, 0.25, 1), // ease
extrapolateRight: "clamp",
});常用 Easing
| Easing | 效果 |
|---|---|
Easing.linear | 線性(預設) |
Easing.ease | 標準緩動 |
Easing.in(Easing.quad) | 加速 |
Easing.out(Easing.quad) | 減速 |
Easing.inOut(Easing.quad) | 先加速後減速 |
Easing.bezier(...) | 自訂貝茲曲線 |
用三角函數做循環動畫
const frame = useCurrentFrame();
// 上下浮動
const floatY = Math.sin(frame * 0.1) * 20;
// 脈動效果
const pulse = 1 + Math.sin(frame * 0.15) * 0.1;
return (
<div
style={{
transform: `translateY(${floatY}px) scale(${pulse})`,
}}
>
浮動元素
</div>
);Math.sin() 的值在 -1 到 1 之間循環,乘以振幅就得到循環動畫。
組合多個動畫
把多個 interpolate 的結果組合:
const frame = useCurrentFrame();
// 位移
const x = interpolate(frame, [0, 60], [-200, 0], {
easing: Easing.out(Easing.cubic),
extrapolateRight: "clamp",
});
// 透明度
const opacity = interpolate(frame, [0, 30], [0, 1], {
extrapolateRight: "clamp",
});
// 旋轉
const rotate = interpolate(frame, [0, 60], [-10, 0], {
easing: Easing.out(Easing.cubic),
extrapolateRight: "clamp",
});
return (
<div
style={{
transform: `translateX(${x}px) rotate(${rotate}deg)`,
opacity,
}}
>
組合動畫
</div>
);spring + interpolate 組合技
先用 spring() 產生 0→1 的進度,再用 interpolate 映射到任意值:
const progress = spring({ frame, fps, config: { damping: 12 } });
// 把 0→1 映射到不同屬性
const scale = interpolate(progress, [0, 1], [0.3, 1]);
const y = interpolate(progress, [0, 1], [100, 0]);
const blur = interpolate(progress, [0, 1], [10, 0]);
return (
<div
style={{
transform: `scale(${scale}) translateY(${y}px)`,
filter: `blur(${blur}px)`,
}}
>
彈跳進場
</div>
);小結
interpolate是值映射函數,多段映射可做淡入→停留→淡出Easing加入非線性緩動效果Math.sin()做循環動畫spring()+interpolate()組合是最強大的動畫模式