Remotion LabRemotion Lab
返回模板庫

先來看第一版

短暫的過場卡片:巨大漸層數字「1」以彈簧動畫衝入畫面,接著「第一版」文字與眼睛圖示漸入,搭配閃爍光點列,邀請觀眾一睹第一版成果。

過場動畫版本展示視覺設計教學
提示詞(可直接修改內容)
import React from "react";
import {
  AbsoluteFill,
  useCurrentFrame,
  useVideoConfig,
  interpolate,
  spring,
} from "remotion";

const colors = {
  background: "#0A0E14",
  backgroundGradient: "linear-gradient(135deg, #0A0E14 0%, #131A24 100%)",
  accent: "#00D4AA",
  accentSecondary: "#4DA3FF",
  warning: "#FFB547",
  danger: "#FF6B6B",
};

const fonts = { main: "'Inter', 'Noto Sans TC', sans-serif" };

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

  const numberSpring = spring({ frame: Math.max(0, frame - 5), fps, config: { damping: 8, mass: 0.6, stiffness: 130 } });
  const numberScale = interpolate(numberSpring, [0, 1], [0.2, 1]);
  const numberOpacity = interpolate(numberSpring, [0, 0.3], [0, 1], { extrapolateRight: "clamp" });
  const ringSpring = spring({ frame: Math.max(0, frame - 10), fps, config: { damping: 10, mass: 0.8, stiffness: 90 } });
  const ringScale = interpolate(ringSpring, [0, 1], [0.4, 1]);
  const ringOpacity = interpolate(ringSpring, [0, 0.5], [0, 0.35], { extrapolateRight: "clamp" });
  const textSpring = spring({ frame: Math.max(0, frame - 30), fps, config: { damping: 10, mass: 0.5, stiffness: 120 } });
  const textTranslateY = interpolate(textSpring, [0, 1], [30, 0]);
  const textOpacity = interpolate(textSpring, [0, 0.4], [0, 1], { extrapolateRight: "clamp" });
  const eyeSpring = spring({ frame: Math.max(0, frame - 45), fps, config: { damping: 10, mass: 0.4, stiffness: 140 } });
  const eyeScale = interpolate(eyeSpring, [0, 1], [0, 1]);
  const eyeOpacity = interpolate(eyeSpring, [0, 0.4], [0, 1], { extrapolateRight: "clamp" });
  const sparkleBase = frame > 50 ? frame - 50 : 0;
  const fadeOut = interpolate(frame, [95, 120], [1, 0], { extrapolateLeft: "clamp", extrapolateRight: "clamp" });
  const glowPulse = interpolate(Math.sin(frame * 0.05), [-1, 1], [0.04, 0.1]);

  return (
    <AbsoluteFill style={{ background: colors.backgroundGradient }}>
      <div style={{ position: "absolute", top: "50%", left: "50%", width: 800, height: 800, borderRadius: "50%", background: `radial-gradient(circle, ${colors.accent}18 0%, transparent 65%)`, transform: "translate(-50%, -50%)", opacity: glowPulse * fadeOut * 10 }} />
      <AbsoluteFill style={{ display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", opacity: fadeOut, gap: 0 }}>
        <div style={{ position: "absolute", display: "flex", alignItems: "center", justifyContent: "center", opacity: ringOpacity * fadeOut, transform: `scale(${ringScale})` }}>
          <svg width="510" height="510" viewBox="0 0 340 340">
            <defs>
              <linearGradient id="fvRingGrad" x1="0" y1="0" x2="1" y2="1">
                <stop offset="0%" stopColor={colors.accent} stopOpacity={0.6} />
                <stop offset="100%" stopColor={colors.accentSecondary} stopOpacity={0.2} />
              </linearGradient>
            </defs>
            <circle cx="170" cy="170" r="155" fill="none" stroke="url(#fvRingGrad)" strokeWidth="2" strokeDasharray="12 8" />
            <circle cx="170" cy="170" r="138" fill="none" stroke={colors.accent} strokeWidth="1" opacity={0.15} />
          </svg>
        </div>
        <div style={{ transform: `scale(${numberScale})`, opacity: numberOpacity, marginBottom: 0, lineHeight: 1 }}>
          <span style={{ fontSize: 420, fontWeight: 900, fontFamily: fonts.main, background: `linear-gradient(135deg, ${colors.accent} 0%, ${colors.accentSecondary} 100%)`, WebkitBackgroundClip: "text", WebkitTextFillColor: "transparent", filter: `drop-shadow(0 0 40px ${colors.accent}60)`, display: "block", lineHeight: 1 }}>1</span>
        </div>
        <div style={{ display: "flex", alignItems: "center", gap: 30, marginTop: 12, opacity: textOpacity, transform: `translateY(${textTranslateY}px)` }}>
          <span style={{ fontSize: 78, fontWeight: 700, fontFamily: fonts.main, color: "rgba(255,255,255,0.88)", letterSpacing: 6 }}>第一版</span>
          <div style={{ transform: `scale(${eyeScale})`, opacity: eyeOpacity, display: "flex", alignItems: "center" }}>
            <svg width="72" height="72" viewBox="0 0 48 48">
              <defs>
                <linearGradient id="fvEyeGrad" x1="0" y1="0" x2="1" y2="1">
                  <stop offset="0%" stopColor={colors.accent} />
                  <stop offset="100%" stopColor={colors.accentSecondary} />
                </linearGradient>
              </defs>
              <path d="M4 24 C10 12, 38 12, 44 24 C38 36, 10 36, 4 24 Z" fill="none" stroke="url(#fvEyeGrad)" strokeWidth="2.5" strokeLinecap="round" />
              <circle cx="24" cy="24" r="7" fill="url(#fvEyeGrad)" opacity={0.9} />
              <circle cx="24" cy="24" r="3.5" fill={colors.background} />
              <circle cx="27" cy="21" r="1.5" fill="white" opacity={0.7} />
            </svg>
          </div>
        </div>
        {sparkleBase > 0 && (
          <div style={{ marginTop: 42, opacity: textOpacity * 0.7 }}>
            <svg width="360" height="30" viewBox="0 0 240 20">
              {[0, 1, 2, 3, 4, 5].map((i) => {
                const sparkleOp = interpolate(Math.sin(sparkleBase * 0.1 + i * 1.1), [-1, 1], [0.15, 0.75]);
                const isAccent = i % 2 === 0;
                return <circle key={i} cx={20 + i * 40} cy={10} r={isAccent ? 3 : 2} fill={isAccent ? colors.accent : colors.accentSecondary} opacity={sparkleOp} />;
              })}
            </svg>
          </div>
        )}
      </AbsoluteFill>
    </AbsoluteFill>
  );
};

登入後查看完整程式碼