Tips & Tricks

Framer Motion with Claude Code

Aprenda sobre framer motion usando o Claude Code. Dicas praticas e exemplos de codigo incluidos.

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>
  );
}

Summary

Framer Motionを使えば、Reactアプリケーションに洗練されたアニメーションを簡単に追加できます。Claude Codeに「このようなアニメーションが欲しい」と伝えるだけで、適切なバリアント設計やイージング設定を生成してくれます。

UIコンポーネントとの組み合わせはRadix UIコンポーネント活用を、デザインシステムの構築はshadcn/ui活用ガイドを参照してください。Framer Motion公式ドキュメントも確認しておきましょう。

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