Remotion LabRemotion Lab
視覺設計動畫數學

動畫數學

深入理解 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() 組合是最強大的動畫模式