Remotion LabRemotion Lab
工具從 Figma 匯入設計

從 Figma 匯入設計

學習如何將 Figma 設計匯出為 SVG,轉換為 React 元件後匯入 Remotion 專案,並為 SVG 元素加入動畫效果。

你可以將 Figma 設計匯出為 SVG 檔案,作為 React 元件匯入 Remotion 專案,然後對其進行動畫製作。


開啟 Figma 設計

本教學以 Streamline 的向量插圖集為範例。你可以使用任何你在 Figma 中製作或引用的設計。


在 Figma 中組織向量元素

如果還沒這麼做,請先在 Figma 中將你想要匯出的元素分組(Group)加入框架(Frame)

在 SVG 中,群組會以 <g> 元素表示。如果你想要同時對多個元素進行動畫,預先在 Figma 中將它們分組,可以讓後續的動畫製作更加方便。


匯出為 SVG

你可以透過以下方式將 Figma 設計複製為 SVG 標記:

  1. 在 Figma 設計中右鍵點擊你想要匯出的元素或群組
  2. 選擇「Copy/Paste as」選項
  3. 選擇「Copy as SVG」

接下來,你需要將 SVG 轉換為 React 元件。通常你可以直接將 SVG 標記貼入 React 的 JSX,它就能正常運作。

或者,你也可以使用 SVGR Playground 來可靠地將 SVG 轉換為 React 元件格式。


在 Remotion 中匯入 SVG

將轉換好的元件貼入 Remotion 專案,並在 src/Root.tsx 中註冊一個 <Composition>

你可以在此範例儲存庫中找到完整的範例。


為 SVG 標記加入動畫

找到你想要動畫的 SVG 元素,為它加入 style 屬性。

以下範例示範如何為包含火箭的 <g> 元素加入動畫。首先建立基本結構,為目標元素加上樣式:

import { AbsoluteFill, useCurrentFrame, useVideoConfig } from "remotion";
 
export const Rocket: React.FC = () => {
  const frame = useCurrentFrame();
  const { fps } = useVideoConfig();
 
  return (
    <AbsoluteFill
      style={{
        backgroundColor: "pink",
        justifyContent: "center",
        alignItems: "center",
      }}
    >
      <svg
        width="800"
        height="800"
        viewBox="0 0 394 394"
        fill="none"
        xmlns="http://www.w3.org/2000/svg"
      >
        <g
          id="vehicle"
          style={{
            transformOrigin: "center center",
            transformBox: "fill-box",
          }}
        >
          {/* 火箭的路徑元素放在這裡 */}
        </g>
      </svg>
    </AbsoluteFill>
  );
};

{ transformOrigin: "center center", transformBox: "fill-box" } 加入元素的樣式,可確保變形的中心點是元素自身的中心,而非整個 SVG 視圖的中心。


建立 Spring 動畫

接下來建立兩個彈簧動畫:一個控制縮放,一個控制位移(向上升空):

import {
  AbsoluteFill,
  useCurrentFrame,
  useVideoConfig,
  spring,
  interpolate,
} from "remotion";
 
export const Rocket: React.FC = () => {
  const frame = useCurrentFrame();
  const { fps } = useVideoConfig();
 
  // 縮放動畫:從 0 到 1,立即開始
  const scale = spring({
    fps,
    frame,
    config: {
      stiffness: 200,
    },
  });
 
  // 升空動畫:從第 20 幀開始,模擬緩慢啟動後加速
  const up = spring({
    fps,
    frame: frame - 20,
    config: {
      damping: 20,
      mass: 15,
    },
  });
 
  // 將 up 的值(0 到 1)映射到像素位移(0 到 -3000px)
  const launch = `translateY(${interpolate(up, [0, 1], [0, -3000])}px)`;
 
  return (
    <AbsoluteFill
      style={{
        backgroundColor: "pink",
        justifyContent: "center",
        alignItems: "center",
      }}
    >
      <svg
        width="800"
        height="800"
        viewBox="0 0 394 394"
        fill="none"
        xmlns="http://www.w3.org/2000/svg"
      >
        <g
          id="vehicle"
          style={{
            // 同時套用縮放和升空動畫
            transform: `scale(${scale}) ${launch}`,
            transformOrigin: "center center",
            transformBox: "fill-box",
          }}
        >
          {/* 火箭的路徑元素放在這裡 */}
        </g>
      </svg>
    </AbsoluteFill>
  );
};

動畫說明

  • scale0 增長到 1,讓火箭在開頭從無到有地出現。
  • up 從第 20 幀開始,配合高 mass(質量)和低 damping(阻尼)模擬重型火箭緩慢啟動的效果。
  • launch 使用 interpolate()up 的值(0 到 1)線性映射到垂直位移(0 到 -3000px),讓火箭向上飛離畫面。

更複雜的 SVG 動畫範例

你可以為 SVG 中的不同元素各自加入獨立的動畫,建立更豐富的效果:

import {
  AbsoluteFill,
  useCurrentFrame,
  useVideoConfig,
  spring,
  interpolate,
} from "remotion";
 
export const AnimatedSvg: React.FC = () => {
  const frame = useCurrentFrame();
  const { fps } = useVideoConfig();
 
  // 各元素的獨立動畫
  const bodyOpacity = interpolate(frame, [0, 15], [0, 1], {
    extrapolateRight: "clamp",
  });
 
  const wingSpread = spring({
    fps,
    frame: frame - 10,
    config: { stiffness: 100, damping: 15 },
  });
 
  const exhaustScale = spring({
    fps,
    frame: frame - 5,
    config: { stiffness: 300, damping: 10 },
  });
 
  return (
    <AbsoluteFill
      style={{
        backgroundColor: "#1a1a2e",
        justifyContent: "center",
        alignItems: "center",
      }}
    >
      <svg
        width="400"
        height="400"
        viewBox="0 0 200 200"
        xmlns="http://www.w3.org/2000/svg"
      >
        {/* 火箭本體:淡入效果 */}
        <g id="body" style={{ opacity: bodyOpacity }}>
          {/* 本體路徑 */}
        </g>
 
        {/* 火箭翼:展開效果 */}
        <g
          id="wings"
          style={{
            transform: `scaleX(${interpolate(wingSpread, [0, 1], [0.2, 1])})`,
            transformOrigin: "center center",
            transformBox: "fill-box",
          }}
        >
          {/* 翼部路徑 */}
        </g>
 
        {/* 引擎噴焰:脈動效果 */}
        <g
          id="exhaust"
          style={{
            transform: `scaleY(${interpolate(exhaustScale, [0, 1], [0, 1])})`,
            transformOrigin: "top center",
            transformBox: "fill-box",
          }}
        >
          {/* 噴焰路徑 */}
        </g>
      </svg>
    </AbsoluteFill>
  );
};

注意事項

  • SVG 坐標系:SVG 的 Y 軸向下為正,因此向上移動要使用負值。
  • transformBox: "fill-box":務必加入此樣式,否則 transformOrigin 會相對於整個 SVG 視圖計算,而非元素自身。
  • 群組與路徑:在 Figma 中良好的圖層命名習慣,可以幫助你在 SVG 程式碼中快速找到要動畫的元素(因為 Figma 會以圖層名稱作為 id)。
  • Locofy 整合:如果你想將整個 Figma 設計匯出為 React 元件(不只是 SVG),可以考慮使用 Locofy

相關資源