Remotion LabRemotion Lab
返回模板庫

Instagram 貼文卡片

模擬 Instagram 貼文的社群媒體卡片動畫,包含頭像、按讚、留言、分享等互動元素,以流暢的分鏡逐一帶入各區塊。

社群簡約橫式
提示詞(可直接修改內容)
import {
  AbsoluteFill,
  interpolate,
  spring,
  useCurrentFrame,
  useVideoConfig,
} from "remotion";
import React from "react";

const USERNAME = "remotion-dev";
const LIKES-TARGET = 1243;
const CAPTION =
  "這是一段示範的 Instagram 貼文內容,展示如何用 Remotion 製作社群媒體動畫。✨ #remotion #動態設計";
const COMMENT-COUNT = 48;

export const IgPostCard: React.FC = () => {
  const frame = useCurrentFrame();
  const { fps } = useVideoConfig();

  // Card scale + fade in: frames 0-20
  const cardProgress = spring({
    frame,
    fps,
    config: { damping: 22, stiffness: 140 },
    durationInFrames: 20,
  });
  const cardScale = interpolate(cardProgress, [0, 1], [0.9, 1]);
  const cardOpacity = interpolate(cardProgress, [0, 0.3], [0, 1], {
    extrapolateRight: "clamp",
  });

  // Top bar slide from top: frames 10-25
  const headerProgress = spring({
    frame: frame - 10,
    fps,
    config: { damping: 20, stiffness: 180 },
    durationInFrames: 15,
  });
  const headerY = interpolate(headerProgress, [0, 1], [-30, 0]);
  const headerOpacity = interpolate(headerProgress, [0, 0.4], [0, 1], {
    extrapolateRight: "clamp",
  });

  // Image fade in: frames 15-30
  const imageOpacity = interpolate(frame, [15, 30], [0, 1], {
    extrapolateLeft: "clamp",
    extrapolateRight: "clamp",
  });

  // Action icons pop in staggered: frames 30-50
  const iconScales = [0, 1, 2, 3].map((i) => {
    const p = spring({
      frame: frame - (30 + i * 5),
      fps,
      config: { damping: 16, stiffness: 200 },
      durationInFrames: 12,
    });
    return interpolate(p, [0, 1], [0, 1], { extrapolateRight: "clamp" });
  });

  // Likes count up: frames 40-75
  const likesRaw = interpolate(frame, [40, 75], [0, 1], {
    extrapolateLeft: "clamp",
    extrapolateRight: "clamp",
  });
  const currentLikes = Math.round(likesRaw * LIKES-TARGET);

  // Caption fade in: frames 50-70
  const captionOpacity = interpolate(frame, [50, 70], [0, 1], {
    extrapolateLeft: "clamp",
    extrapolateRight: "clamp",
  });

  // Comments/timestamp fade in: frames 65-80
  const footerOpacity = interpolate(frame, [65, 80], [0, 1], {
    extrapolateLeft: "clamp",
    extrapolateRight: "clamp",
  });

  return (
    <AbsoluteFill
      style={{
        background: "#0f0f0f",
        justifyContent: "center",
        alignItems: "center",
      }}
    >
      {/* Card */}
      <div
        style={{
          transform: `scale(${cardScale})`,
          opacity: cardOpacity,
          background: "#ffffff",
          borderRadius: 12,
          width: 860,
          boxSizing: "border-box",
          fontFamily: "sans-serif",
          overflow: "hidden",
          boxShadow: "0 32px 80px rgba(0,0,0,0.6)",
        }}
      >
        {/* Top bar: avatar + username + follow + menu */}
        <div
          style={{
            display: "flex",
            alignItems: "center",
            padding: "16px 20px",
            gap: 12,
            transform: `translateY(${headerY}px)`,
            opacity: headerOpacity,
          }}
        >
          {/* Avatar */}
          <div
            style={{
              width: 44,
              height: 44,
              borderRadius: "50%",
              background: "linear-gradient(135deg, #f09433, #e6683c, #dc2743, #cc2366, #bc1888)",
              border: "2px solid transparent",
              flexShrink: 0,
              display: "flex",
              alignItems: "center",
              justifyContent: "center",
              fontSize: 18,
              fontWeight: 700,
              color: "#ffffff",
            }}
          >
            R
          </div>

          {/* Username */}
          <div style={{ flex: 1 }}>
            <span
              style={{
                fontSize: 16,
                fontWeight: 700,
                color: "#0f0f0f",
                lineHeight: 1,
              }}
            >
              {USERNAME}
            </span>
          </div>

          {/* Follow button */}
          <div
            style={{
              border: "1.5px solid #0095f6",
              borderRadius: 8,
              padding: "6px 16px",
              fontSize: 14,
              fontWeight: 600,
              color: "#0095f6",
              cursor: "pointer",
            }}
          >
            追蹤
          </div>

          {/* Menu */}
          <div
            style={{
              fontSize: 20,
              color: "#262626",
              fontWeight: 700,
              marginLeft: 8,
              letterSpacing: 1,
            }}
          >
            •••
          </div>
        </div>

        {/* Image placeholder */}
        <div
          style={{
            width: 860,
            height: 480,
            background: "linear-gradient(135deg, #667eea 0%, #764ba2 40%, #f093fb 80%, #f5576c 100%)",
            opacity: imageOpacity,
            position: "relative",
            display: "flex",
            alignItems: "center",
            justifyContent: "center",
            overflow: "hidden",
          }}
        >
          {/* Subtle grid overlay */}
          <div
            style={{
              position: "absolute",
              inset: 0,
              backgroundImage:
                "repeating-linear-gradient(0deg, rgba(255,255,255,0.05) 0px, rgba(255,255,255,0.05) 1px, transparent 1px, transparent 40px), repeating-linear-gradient(90deg, rgba(255,255,255,0.05) 0px, rgba(255,255,255,0.05) 1px, transparent 1px, transparent 40px)",
            }}
          />
          <div
            style={{
              fontSize: 48,
              color: "rgba(255,255,255,0.6)",
              fontWeight: 300,
              letterSpacing: 4,
              position: "relative",
              zIndex: 1,
            }}
          >
            Remotion
          </div>
        </div>

        {/* Action row */}
        <div
          style={{
            display: "flex",
            alignItems: "center",
            padding: "12px 16px",
          }}
        >
          {/* Left icons: heart, comment, share */}
          {[
            { icon: "♡", idx: 0 },
            { icon: "💬", idx: 1 },
            { icon: "↗", idx: 2 },
          ].map(({ icon, idx }) => (
            <div
              key={icon}
              style={{
                transform: `scale(${iconScales[idx]})`,
                fontSize: 26,
                marginRight: 16,
                cursor: "pointer",
                color: "#262626",
              }}
            >
              {icon}
            </div>
          ))}

          {/* Spacer */}
          <div style={{ flex: 1 }} />

          {/* Bookmark */}
          <div
            style={{
              transform: `scale(${iconScales[3]})`,
              fontSize: 26,
              color: "#262626",
              cursor: "pointer",
            }}
          >
            🔖
          </div>
        </div>

        {/* Likes count */}
        <div
          style={{
            padding: "0 16px 8px",
            fontSize: 15,
            color: "#262626",
          }}
        >
          <span style={{ fontWeight: 700 }}>
            {currentLikes.toLocaleString()} 人
          </span>
          按讚
        </div>

        {/* Caption */}
        <div
          style={{
            padding: "0 16px 8px",
            fontSize: 15,
            color: "#262626",
            lineHeight: 1.5,
            opacity: captionOpacity,
          }}
        >
          <span style={{ fontWeight: 700, marginRight: 6 }}>{USERNAME}</span>
          {CAPTION}
        </div>

        {/* Comments */}
        <div
          style={{
            padding: "0 16px 6px",
            fontSize: 15,
            color: "#8e8e8e",
            opacity: footerOpacity,
          }}
        >
          查看全部 {COMMENT-COUNT} 則留言
        </div>

        {/* Timestamp */}
        <div
          style={{
            padding: "0 16px 16px",
            fontSize: 12,
            color: "#c7c7c7",
            textTransform: "uppercase",
            letterSpacing: 0.5,
            opacity: footerOpacity,
          }}
        >
          3小時前
        </div>
      </div>
    </AbsoluteFill>
  );
};

登入後查看完整程式碼