Remotion LabRemotion Lab
返回模板庫

AI 只能讀取線條、顏色、文字

用三個 SVG 圖示動畫揭示 AI 視覺感知的本質:只能理解線條、顏色、文字三種元素,並以掃描線特效強調讀取過程。

AI工具視覺理解SVG動畫教學
提示詞

我有一個用 Remotion 寫的場景元件(檔案:Scene47_AiReadsOnly.tsx),請幫我做以下調整: 1. 修改三個元素的標籤(目前是:線條、顏色、文字) 2. 調整各元素圖示的主色(目前依序使用 accent #00D4AA、warning #FFB547、accentSecondary #4DA3FF) 3. 更改標題文字(目前是「AI 只能讀取」) 4. 修改掃描線顏色與速度 請保留原本的動畫效果,只修改我指定的部分,然後把完整的修改後程式碼給我。

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",
  dimmed: "rgba(255, 255, 255, 0.6)",
};

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

const ELEMENTS = [
  { label: "線條", color: "#00D4AA" },
  { label: "顏色", color: "#FFB547" },
  { label: "文字", color: "#4DA3FF" },
];

const LineIcon: React.FC<{ color: string; progress: number; frame: number }> = ({ color, progress, frame }) => {
  const dashLen = interpolate(progress, [0, 1], [0, 300]);
  const wave = Math.sin(frame * 0.06) * 8;
  return (
    <svg width="270" height="270" viewBox="-90 -90 180 180">
      <circle cx={0} cy={0} r={80} fill={`${color}08`} stroke={`${color}25`} strokeWidth={2} />
      <path d={`M-50,${-20 + wave} Q-20,${-40 + wave} 0,${-15 + wave} T50,${-25 + wave}`} fill="none" stroke={color} strokeWidth={4} strokeLinecap="round" strokeDasharray={300} strokeDashoffset={300 - dashLen} opacity={0.9} />
      <path d={`M-50,${10 - wave * 0.5} Q-10,${30 - wave * 0.5} 20,${5 - wave * 0.5} T50,${15 - wave * 0.5}`} fill="none" stroke={color} strokeWidth={3} strokeLinecap="round" strokeDasharray={300} strokeDashoffset={300 - dashLen * 0.8} opacity={0.6} />
      <path d={`M-40,${35 + wave * 0.3} L0,${40 + wave * 0.3} L40,${30 + wave * 0.3}`} fill="none" stroke={color} strokeWidth={2.5} strokeLinecap="round" strokeDasharray={300} strokeDashoffset={300 - dashLen * 0.6} opacity={0.4} />
    </svg>
  );
};

const ColorIcon: React.FC<{ color: string; progress: number; frame: number }> = ({ color, progress, frame }) => {
  const rot = interpolate(frame, [0, 180], [0, 360]);
  return (
    <svg width="270" height="270" viewBox="-90 -90 180 180">
      <circle cx={0} cy={0} r={80} fill={`${color}08`} stroke={`${color}25`} strokeWidth={2} />
      {[0, 60, 120, 180, 240, 300].map((angle, i) => {
        const segColors = ["#FF6B6B", "#FFB547", "#2ECC71", "#4DA3FF", "#9B59B6", "#00D4AA"];
        const rad = ((angle + rot * 0.3) * Math.PI) / 180;
        const r = 38;
        const x = Math.cos(rad) * r;
        const y = Math.sin(rad) * r;
        const s = interpolate(progress, [0, 1], [0, 1]);
        return <circle key={i} cx={x} cy={y} r={interpolate(s, [0, 1], [0, 18])} fill={segColors[i]} opacity={interpolate(s, [0, 1], [0, 0.7])} />;
      })}
      <circle cx={0} cy={0} r={10 * progress} fill="#FFF" opacity={0.5 * progress} />
    </svg>
  );
};

const TextIcon: React.FC<{ color: string; progress: number; frame: number }> = ({ color, progress, frame }) => {
  const blink = Math.sin(frame * 0.15) > 0 ? 1 : 0.3;
  return (
    <svg width="270" height="270" viewBox="-90 -90 180 180">
      <circle cx={0} cy={0} r={80} fill={`${color}08`} stroke={`${color}25`} strokeWidth={2} />
      <text x={0} y={8} textAnchor="middle" fontSize={56} fontWeight={800} fontFamily={fonts.main} fill={color} opacity={interpolate(progress, [0, 1], [0, 0.85])}>Aa</text>
      <rect x={38} y={-18} width={4} height={48} rx={2} fill="#FFF" opacity={progress > 0.5 ? blink * 0.6 : 0} />
      <line x1={-35} y1={30} x2={interpolate(progress, [0, 1], [-35, 35])} y2={30} stroke={color} strokeWidth={3} strokeLinecap="round" opacity={0.4} />
    </svg>
  );
};

const ICONS = [LineIcon, ColorIcon, TextIcon];

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

  const titleSpring = spring({ frame: Math.max(0, frame - 5), fps, config: { damping: 10, mass: 0.6, stiffness: 110 } });
  const titleScale = interpolate(titleSpring, [0, 1], [0.5, 1]);
  const titleOp = interpolate(titleSpring, [0, 0.4], [0, 1], { extrapolateRight: "clamp" });
  const iconSprings = ELEMENTS.map((_, i) => spring({ frame: Math.max(0, frame - (35 + i * 20)), fps, config: { damping: 10, mass: 0.5, stiffness: 120 } }));
  const labelSprings = ELEMENTS.map((_, i) => spring({ frame: Math.max(0, frame - (50 + i * 20)), fps, config: { damping: 12, mass: 0.4, stiffness: 150 } }));
  const scanProgress = interpolate(frame, [80, 130], [0, 1], { extrapolateLeft: "clamp", extrapolateRight: "clamp" });
  const allGlow = interpolate(frame, [120, 140], [0, 1], { extrapolateLeft: "clamp", extrapolateRight: "clamp" });
  const fadeOut = interpolate(frame, [150, 180], [1, 0], { extrapolateLeft: "clamp", extrapolateRight: "clamp" });
  const bgPulse = interpolate(Math.sin(frame * 0.04), [-1, 1], [0.03, 0.08]);

  return (
    <AbsoluteFill style={{ background: colors.backgroundGradient }}>
      <div style={{ position: "absolute", top: "50%", left: "50%", width: 1100, height: 1100, borderRadius: "50%", background: `radial-gradient(circle, ${colors.accentSecondary}08 0%, transparent 60%)`, transform: "translate(-50%, -50%)", opacity: bgPulse * fadeOut }} />
      <AbsoluteFill style={{ display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", gap: 75, opacity: fadeOut }}>
        <div style={{ fontSize: 108, fontWeight: 800, fontFamily: fonts.main, letterSpacing: 6, opacity: titleOp, transform: `scale(${titleScale})`, textAlign: "center" }}>
          <span style={{ color: colors.accentSecondary }}>AI</span>
          <span style={{ color: "#FFFFFFcc" }}> 只能讀取</span>
        </div>
        <div style={{ display: "flex", alignItems: "center", gap: 90 }}>
          {ELEMENTS.map((el, i) => {
            const iconScale = interpolate(iconSprings[i], [0, 1], [0.2, 1]);
            const iconOp = interpolate(iconSprings[i], [0, 0.3], [0, 1], { extrapolateRight: "clamp" });
            const labelOp = interpolate(labelSprings[i], [0, 0.5], [0, 1], { extrapolateRight: "clamp" });
            const floatY = Math.sin(frame * 0.05 + i * 2) * 5;
            const glowIntensity = allGlow > 0 ? Math.sin(frame * 0.08 + i * 1.2) * 0.3 + 0.7 : 0;
            const IconComponent = ICONS[i];
            return (
              <div key={el.label} style={{ display: "flex", flexDirection: "column", alignItems: "center", gap: 30, opacity: iconOp, transform: `scale(${iconScale}) translateY(${floatY}px)` }}>
                <div style={{ position: "relative" }}>
                  {glowIntensity > 0 && <div style={{ position: "absolute", inset: -8, borderRadius: "50%", border: `2px solid ${el.color}`, opacity: glowIntensity * 0.35 }} />}
                  <IconComponent color={el.color} progress={iconSprings[i]} frame={frame} />
                </div>
                <div style={{ fontSize: 63, fontWeight: 700, fontFamily: fonts.main, color: el.color, opacity: labelOp, letterSpacing: 4, filter: glowIntensity > 0 ? `drop-shadow(0 0 12px ${el.color}50)` : "none" }}>
                  {el.label}
                </div>
              </div>
            );
          })}
        </div>
        {scanProgress > 0 && scanProgress < 1 && (
          <div style={{ position: "absolute", left: 0, right: 0, height: 3, background: `linear-gradient(90deg, transparent, ${colors.accentSecondary}60, transparent)`, top: `${interpolate(scanProgress, [0, 1], [20, 80])}%`, opacity: 0.6, boxShadow: `0 0 20px ${colors.accentSecondary}40` }} />
        )}
      </AbsoluteFill>
    </AbsoluteFill>
  );
};

登入後查看完整程式碼