motion について
Motionは、JavaScript、React、Vueでインターフェースを開発する人向けのアニメーションライブラリです。ジェスチャー、スクロール、レイアウトのアニメーションに対応し、LazyMotionでバンドルサイズを抑えられます。
主な機能
- 01JavaScript、React、Vueのアニメーション
- 02スクロール・ビューポートアニメーション
- 03ドラッグとジェスチャー操作
- 04Variantsによるアニメーション制御
- 05LazyMotionによるバンドル最適化
活用シーン
- 01Webアプリの要素に動きを付ける
- 02子要素のアニメーションを順序付ける
- 03スクロールや表示を契機とする効果の作成
- 04Reactでアニメーションのバンドルサイズを抑える
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ lucking7/ motiondev-skills --skill motionインストール後、Claude Code で/motionを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
reference/examples.jsonexamples.mdjavascript.mdreact.mdvue.mdscripts/get-example.shsearch-examples.sh詳細
モーションアニメーションライブラリ
Motion(パッケージ:motion、以前の名称はframer-motion)は、JavaScript、React、Vue向けの業界標準アニメーションライブラリです。
インストール
npm install motion # React/JS
npm install motion-v # Vue
プラットフォーム別クイックリファレンス
JavaScript
import { animate, scroll, inView, stagger, hover, press } from "motion"
// Basic animation
animate("#box", { x: 100, opacity: 1 })
// With spring physics
animate(element, { scale: 1.2 }, { type: "spring", stiffness: 300, damping: 30 })
// Staggered list
animate("li", { opacity: 1 }, { delay: stagger(0.1) })
// Scroll-linked
scroll(animate("#progress", { scaleX: [0, 1] }))
// Viewport detection
inView(".card", ({ target }) => {
animate(target, { opacity: 1, y: 0 })
})
// Gestures
hover(".btn", el => {
animate(el, { scale: 1.1 })
return () => animate(el, { scale: 1 })
})
press(".btn", el => {
animate(el, { scale: 0.95 })
return () => animate(el, { scale: 1 })
})
React
import { motion, AnimatePresence, useScroll, useTransform } from "motion/react"
// Basic motion component
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0 }}
transition={{ type: "spring" }}
/>
// Gestures
<motion.button
whileHover={{ scale: 1.1 }}
whileTap={{ scale: 0.95 }}
drag="x"
dragConstraints={{ left: 0, right: 100 }}
/>
// Layout animations
<motion.div layout layoutId="shared-element" />
// Scroll animations
const { scrollYProgress } = useScroll()
const y = useTransform(scrollYProgress, [0, 1], [0, -300])
<motion.div style={{ y }} />
Vue
<script setup>
import { motion, AnimatePresence } from "motion-v"
</script>
<template>
<motion.div
:initial="{ opacity: 0 }"
:animate="{ opacity: 1 }"
:exit="{ opacity: 0 }"
:whileHover="{ scale: 1.1 }"
/>
</template>
コア API
| API | プラットフォーム | 説明 |
|---|---|---|
animate() | すべて | スプリング/トゥイーンで要素をアニメーション化 |
scroll() | JS | スクロール連動アニメーション |
inView() | JS | ビューポートの検出 |
hover() | JS | ホバージェスチャー |
press() | JS | 押下/タップジェスチャー |
stagger() | すべて | 遅延をずらす |
React 固有
| API | 説明 |
|---|---|
motion.div | Motion で拡張された要素 |
AnimatePresence | 終了時のアニメーション |
LayoutGroup | レイアウトアニメーションの調整 |
LazyMotion | バンドルの最適化(約4.6kb) |
useMotionValue() | リアクティブなアニメーション値 |
useTransform() | 派生モーション値 |
useSpring() | スプリングアニメーション値 |
useScroll() | スクロールの進行状況 |
useAnimate() | 命令型の制御 |
トランジションオプション
スプリング(物理ベース)
{
type: "spring",
stiffness: 300, // Higher = snappier
damping: 30, // Higher = less bounce
mass: 1, // Higher = more momentum
bounce: 0.25, // 0-1, alternative to stiffness/damping
visualDuration: 0.5
}
トゥイーン(時間ベース)
{
duration: 0.5,
ease: "easeInOut", // or cubic bezier [0.4, 0, 0.2, 1]
delay: 0.2,
repeat: Infinity,
repeatType: "reverse" // "loop" | "mirror"
}
イージング関数
"linear"、"easeIn"、"easeOut"、"easeInOut"、"circIn"、"circOut"、"backIn"、"backOut"、"anticipate"
よく使われるパターン
AnimatePresence(終了時のアニメーション)
// CRITICAL: AnimatePresence must stay mounted, children need unique keys
<AnimatePresence>
{isVisible && (
<motion.div
key="modal"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
/>
)}
</AnimatePresence>
レイアウトアニメーション
<motion.div layout>
{isExpanded ? <FullContent /> : <Summary />}
</motion.div>
// Shared element transitions
<motion.div layoutId="card-123" />
スクロールアニメーション
// Viewport-triggered
<motion.div
initial={{ opacity: 0, y: 50 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: "-100px" }}
/>
// Scroll-linked
const { scrollYProgress } = useScroll()
const y = useTransform(scrollYProgress, [0, 1], [0, -300])
<motion.div style={{ y }} />
ドラッグジェスチャー
<motion.div
drag="x"
dragConstraints={{ left: 0, right: 300 }}
dragElastic={0.2}
dragMomentum={true}
dragSnapToOrigin
/>
SVG の線描画
<motion.path
initial={{ pathLength: 0 }}
animate={{ pathLength: 1 }}
transition={{ duration: 2, ease: "easeInOut" }}
/>
バリアント(オーケストレーション)
const container = {
hidden: { opacity: 0 },
show: {
opacity: 1,
transition: { staggerChildren: 0.1 }
}
}
const item = {
hidden: { opacity: 0, y: 20 },
show: { opacity: 1, y: 0 }
}
<motion.ul variants={container} initial="hidden" animate="show">
<motion.li variants={item} />
<motion.li variants={item} />
</motion.ul>
パフォーマンス
バンドルサイズの最適化
// Full bundle: ~34 KB
import { motion } from "motion/react"
// Optimized: ~4.6 KB
import { LazyMotion, domAnimation, m } from "motion/react"
<LazyMotion features={domAnimation}>
<m.div animate={{ x: 100 }} />
</LazyMotion>
// Minimal: 2.3 KB
import { useAnimate } from "motion/react"
Tailwind との競合を避ける
// WRONG - causes stuttering
<motion.div className="transition-all" animate={{ x: 100 }} />
// CORRECT
<motion.div animate={{ x: 100 }} />
Next.js との統合
App Router(RSC)
// components/motion-client.tsx
"use client"
import * as motion from "motion/react-client"
export { motion }
// app/page.tsx
import { motion } from "@/components/motion-client"
クライアントコンポーネントを直接使用
"use client"
import { motion } from "motion/react"
アクセシビリティ
import { MotionConfig } from "motion/react"
<MotionConfig reducedMotion="user">
<App />
</MotionConfig>
トラブルシューティング
AnimatePresence の終了時アニメーションが機能しない
問題:終了時のアニメーションが再生されない 原因:
- AnimatePresence が子と一緒にアンマウントされる
- 一意の
keyprop がない - 子が直接の子孫ではない
解決策:
// WRONG
{isVisible && <AnimatePresence><motion.div /></AnimatePresence>}
// CORRECT
<AnimatePresence>
{isVisible && <motion.div key="unique" exit={{ opacity: 0 }} />}
</AnimatePresence>
スクロール可能なコンテナのレイアウト問題
<motion.div layoutScroll style={{ overflow: "auto" }}>
<motion.div layout />
</motion.div>
固定位置のレイアウト問題
<motion.div layoutRoot style={{ position: "fixed" }}>
<motion.div layout />
</motion.div>
レイアウトの拡大縮小による歪み
// Set borderRadius/boxShadow via style for scale correction
<motion.div layout style={{ borderRadius: 20, boxShadow: "..." }} />
大きなリストのパフォーマンス
仮想化ライブラリを使用してください:react-window、react-virtuoso、@tanstack/react-virtual
リファレンスドキュメント
プラットフォーム別の詳細なドキュメントについては、reference/ フォルダーを参照してください:
reference/react.md- React コンポーネントとフックreference/javascript.md- Vanilla JS APIreference/vue.md- Vue ディレクティブとコンポーネントreference/examples.md- カテゴリー別のサンプル一覧
リソース
コメント
Markdown 対応