Tips & Tricks

Framer Motion: Claude Code 활용 가이드

framer motion: Claude Code 활용. 실용적인 팁과 코드 예시를 포함합니다.

Framer Motionで洗練された애니메이션を구축する

Framer MotionはReact向けの宣言的애니메이션라이브러리です。CSS애니메이션では難しい複雑なインタラクションや레이아웃애니메이션を、直感的なAPIで구현할 수 있습니다。Claude Code는 애니메이션설계から細かなイージング調整まで的確にサポートしてくれます。

기본적인애니메이션

Claude Code에애니메이션付きの컴포넌트を依頼합시다。

> Framer Motionでカード목록の애니메이션を作って。
> マウント時のスタガー표시、호버時の拡大、클릭時のフィードバック付きで。
import { motion, AnimatePresence } from "framer-motion";

const containerVariants = {
  hidden: { opacity: 0 },
  visible: {
    opacity: 1,
    transition: {
      staggerChildren: 0.1,
    },
  },
};

const cardVariants = {
  hidden: { opacity: 0, y: 20 },
  visible: {
    opacity: 1,
    y: 0,
    transition: { duration: 0.4, ease: "easeOut" },
  },
};

function CardList({ items }: { items: Item[] }) {
  return (
    <motion.div
      variants={containerVariants}
      initial="hidden"
      animate="visible"
      className="grid grid-cols-3 gap-4"
    >
      {items.map((item) => (
        <motion.div
          key={item.id}
          variants={cardVariants}
          whileHover={{ scale: 1.03, boxShadow: "0 8px 30px rgba(0,0,0,0.12)" }}
          whileTap={{ scale: 0.98 }}
          className="p-6 bg-white rounded-lg shadow"
        >
          <h3>{item.title}</h3>
          <p>{item.description}</p>
        </motion.div>
      ))}
    </motion.div>
  );
}

AnimatePresenceでマウント・アンマウント

要素の추가・삭제に애니메이션を付けるパターンです。

function NotificationStack({ notifications }: { notifications: Notification[] }) {
  return (
    <div className="fixed top-4 right-4 space-y-2">
      <AnimatePresence mode="popLayout">
        {notifications.map((notification) => (
          <motion.div
            key={notification.id}
            initial={{ opacity: 0, x: 100, scale: 0.9 }}
            animate={{ opacity: 1, x: 0, scale: 1 }}
            exit={{ opacity: 0, x: 100, scale: 0.9 }}
            transition={{ type: "spring", stiffness: 300, damping: 25 }}
            layout
            className="bg-white p-4 rounded-lg shadow-lg min-w-[300px]"
          >
            <p>{notification.message}</p>
          </motion.div>
        ))}
      </AnimatePresence>
    </div>
  );
}

레이아웃애니메이션

layout프로퍼티を使って、레이아웃변경時のスムーズな애니메이션を実現할 수 있습니다。

function FilterableGrid({ items }: { items: Item[] }) {
  const [filter, setFilter] = useState("all");

  const filteredItems = items.filter(
    (item) => filter === "all" || item.category === filter
  );

  return (
    <div>
      <div className="flex gap-2 mb-4">
        {["all", "design", "dev", "marketing"].map((f) => (
          <motion.button
            key={f}
            onClick={() => setFilter(f)}
            className={`px-4 py-2 rounded ${filter === f ? "bg-blue-500 text-white" : "bg-gray-200"}`}
            whileHover={{ scale: 1.05 }}
            whileTap={{ scale: 0.95 }}
          >
            {f}
          </motion.button>
        ))}
      </div>

      <motion.div layout className="grid grid-cols-3 gap-4">
        <AnimatePresence>
          {filteredItems.map((item) => (
            <motion.div
              key={item.id}
              layout
              initial={{ opacity: 0, scale: 0.8 }}
              animate={{ opacity: 1, scale: 1 }}
              exit={{ opacity: 0, scale: 0.8 }}
              transition={{ duration: 0.3 }}
              className="p-4 bg-white rounded-lg"
            >
              {item.title}
            </motion.div>
          ))}
        </AnimatePresence>
      </motion.div>
    </div>
  );
}

스크롤連動애니메이션

useScrolluseTransformで스크롤位置に連動する애니메이션を구현します。

import { motion, useScroll, useTransform } from "framer-motion";

function ParallaxHero() {
  const { scrollY } = useScroll();
  const y = useTransform(scrollY, [0, 500], [0, -150]);
  const opacity = useTransform(scrollY, [0, 300], [1, 0]);
  const scale = useTransform(scrollY, [0, 300], [1, 0.8]);

  return (
    <motion.div
      style={{ y, opacity, scale }}
      className="h-screen flex items-center justify-center"
    >
      <h1 className="text-6xl font-bold">Welcome</h1>
    </motion.div>
  );
}

function ScrollReveal({ children }: { children: React.ReactNode }) {
  const ref = useRef(null);
  const { scrollYProgress } = useScroll({
    target: ref,
    offset: ["start end", "end start"],
  });

  const opacity = useTransform(scrollYProgress, [0, 0.3], [0, 1]);
  const y = useTransform(scrollYProgress, [0, 0.3], [50, 0]);

  return (
    <motion.div ref={ref} style={{ opacity, y }}>
      {children}
    </motion.div>
  );
}

ジェスチャー애니메이션

드래그やスワイプなどのジェスチャーに대응した애니메이션です。

function DraggableCard() {
  return (
    <motion.div
      drag
      dragConstraints={{ left: -100, right: 100, top: -50, bottom: 50 }}
      dragElastic={0.2}
      dragTransition={{ bounceStiffness: 300, bounceDamping: 20 }}
      whileDrag={{ scale: 1.1, cursor: "grabbing" }}
      className="w-48 h-48 bg-blue-500 rounded-xl cursor-grab"
    />
  );
}

function SwipeCard({ onSwipe }: { onSwipe: (dir: string) => void }) {
  return (
    <motion.div
      drag="x"
      dragConstraints={{ left: 0, right: 0 }}
      onDragEnd={(_, info) => {
        if (info.offset.x > 100) onSwipe("right");
        if (info.offset.x < -100) onSwipe("left");
      }}
      className="p-8 bg-white rounded-xl shadow-lg"
    >
      スワイプしてください
    </motion.div>
  );
}

정리

Framer Motionを使えば、React애플리케이션に洗練された애니메이션を簡単に추가할 수 있습니다。Claude Code에「こ와 같은애니메이션が欲しい」と伝える만으로、적절한バリアント설계やイージング설정を생성してくれます。

UI컴포넌트との組み合わせはRadix UI컴포넌트활용を、デザインシステムの구축はshadcn/ui활용가이드를 참고하세요.Framer Motion공식 문서도 확인해 두세요.

#Claude Code #Framer Motion #React #animation #UI/UX