mcpField
M
motion-principles

motion-principles

github.com/athevonデザイン・UI6981.1k 回インストール3 週間前に更新
リポジトリ

motion-principles について

motion-principlesは、Claude Code、claude.ai、Cowork向けのクリエイティブコーディングスキルで、Web、Android、Appleのモーションとインタラクション設計を扱います。時間設定、イージング、アクセシビリティ、パフォーマンスの指針と、各プラットフォームの詳細スキルを提供します。

主な機能

  1. 01クロスプラットフォームのモーション指針
  2. 02時間とイージングの推奨
  3. 03視覚効果の軽減に関するアクセシビリティ指針
  4. 04アニメーション性能チェックリスト
  5. 05プラットフォーム別スキルへの案内

活用シーン

  1. 01UIトランジションの挙動設計
  2. 02視覚効果の軽減設定への対応確認
  3. 03アニメーションの滑らかさと性能の改善

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/athevon/genjutsu --skill motion-principles

インストール後、Claude Code で/motion-principlesを入力して読み込まれたか確認します。

詳細

バージョン依存です。 以下のすべての API 名、SDK の要件、ブラウザーサポートに関する記述は、 2026-09-08 に一次資料と照合して確認済みです。照合した対象と時期については、 _jutsu/VERSIONS.md をご覧ください。この日付が古い場合は、バージョン番号に基づいて行動する前に再確認してください。

モーションの原則

基礎となる原則です。すべてのクリエイティブスキルの呼び出し時に読み込まれます。 ここでは簡潔なルールを説明します。詳しくは references/ をご覧ください。


タイミングのルール

コンテキスト時間理由
マイクロインタラクション(切り替え、ホバー、フォーカス)100-150ms即座にフィードバックし、遅延を感じさせません
UI の遷移(モーダル、ドロワー、タブ切り替え)200-300ms滑らかで、もたつきません
ページ/ルートの遷移300-500ms空間的なストーリーを生み出します
スクロール連動/3D自由(進行状況に基づく)ユーザー入力に連動するため、固定の時間はありません

頻度のルール: アニメーションが頻繁に再生されるほど、短く控えめにする必要があります。 ボタンのホバー(1日1000回)=不透明度の変化を100ms。オンボーディングの表示(生涯で1回)=600ms以上の完全な演出。


イージング早見表

動作イージング理由
要素が入るease-out / スプリング静止位置に向けて減速し、自然に収まります
要素が出るease-in離れるときに加速し、邪魔にならないようにします
要素が状態間を移動するease-in-out滑らかに開始し、滑らかに停止します
スクロール連動linear / none入力と1対1で連動し、遅延を感じさせません
弾む/遊び心のある動きスプリング(不足減衰)オーバーシュートによって生き生きとした動きになります
きびきびした UIcubic-bezier(0.2, 0, 0, 1)速く始まり、滑らかに収まります

退出は常に、出現より控えめにします。 出現:300msの ease-out、完全な演出。退出:200msの ease-in、不透明度のみ。

ネイティブのイージング相当値(クロスプラットフォーム)
Web(CSS / JS)SwiftUICompose
cubic-bezier(0.2, 0, 0, 1).spring(response: 0.4, dampingFraction: 0.85) または .snappyspring(stiffness = Spring.StiffnessMedium, dampingRatio = 0.85f)
ease-out.easeOut(duration: 0.3)tween(durationMillis = 300, easing = LinearOutSlowInEasing)
ease-in.easeIn(duration: 0.2)tween(durationMillis = 200, easing = FastOutLinearInEasing)
スプリング(弾む).bouncy(iOS 17+)spring(stiffness = Spring.StiffnessLow, dampingRatio = Spring.DampingRatioMediumBouncy)
スプリング(滑らか).smooth(iOS 17+)spring(stiffness = Spring.StiffnessMedium, dampingRatio = Spring.DampingRatioNoBouncy)

アクセシビリティ(必須)

モーションの軽減 - 必須

すべてのアニメーションコンポーネントは、ユーザーのモーション軽減設定に従う必要があります。プラットフォームを問わず、例外はありません。

プラットフォームAPI
Web CSS@media (prefers-reduced-motion: reduce)
Web JSwindow.matchMedia('(prefers-reduced-motion: reduce)')
SwiftUI@Environment(\.accessibilityReduceMotion) var reduceMotion
UIKitUIAccessibility.isReduceMotionEnabled(および reduceMotionStatusDidChangeNotification)
ComposeSettings.Global.ANIMATOR_DURATION_SCALE を使ったカスタムヘルパー(詳しくは mobile-principles/references/accessibility-mobile.md を参照)

CSS:

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

SwiftUI:

struct AnimatedView: View {
    @Environment(\.accessibilityReduceMotion) var reduceMotion
    @State var visible = false

    var body: some View {
        Text("Hello")
            .opacity(visible ? 1 : 0)
            .animation(reduceMotion ? .none : .spring(response: 0.4, dampingFraction: 0.85), value: visible)
    }
}

Compose:

@Composable
fun rememberReduceMotion(): Boolean {
    val context = LocalContext.current
    return remember {
        Settings.Global.getFloat(context.contentResolver, Settings.Global.ANIMATOR_DURATION_SCALE, 1f) == 0f
    }
}

@Composable
fun AnimatedComponent(visible: Boolean) {
    val reduce = rememberReduceMotion()
    val alpha by animateFloatAsState(
        targetValue = if (visible) 1f else 0f,
        animationSpec = if (reduce) snap() else spring(stiffness = Spring.StiffnessMedium)
    )
}
その他の a11y 要件
  • フォーカスインジケーターをアニメーションで隠してはいけません
  • アニメーションコンテンツは、すべてのフレームで WCAG のコントラスト比を満たす必要があります(遷移中にテキストがフェードして見えなくなることがないようにします)
  • ループアニメーションには、一時停止する手段を用意してください

あらゆる場面での「禁止」ルール

1. width/height/top/left はアニメーションさせない

フレームごとにレイアウトの再計算が発生し、カクつきます。

/* BAD */
.drawer { transition: height 0.3s ease; }
.drawer.open { height: 400px; }

/* GOOD */
.drawer { transition: transform 0.3s ease-out; transform: translateY(100%); }
.drawer.open { transform: translateY(0); }

SwiftUI 相当(BAD と GOOD):

// BAD - animates frame (causes layout pass)
.frame(height: open ? 400 : 0)
.animation(.easeInOut, value: open)

// GOOD - animates transform via offset
.offset(y: open ? 0 : 400)
.animation(.spring(), value: open)

Compose 相当(BAD と GOOD):

// BAD - animates size (full layout pass)
val height by animateDpAsState(if (open) 400.dp else 0.dp)

// GOOD - animates Y offset via graphicsLayer
val translation by animateFloatAsState(if (open) 0f else 400f)
Box(modifier = Modifier.graphicsLayer { translationY = translation })
2. scale を 0 にしない

scale(0) を使うと、要素がブラックホールに消えるように見えます。必ず最小値を保ってください。

/* BAD */
.modal-exit { transform: scale(0); }

/* GOOD */
.modal-exit { transform: scale(0.95); opacity: 0; }

SwiftUI 相当:

// BAD
.scaleEffect(visible ? 1.0 : 0.0)

// GOOD
.scaleEffect(visible ? 1.0 : 0.95)
.opacity(visible ? 1.0 : 0.0)

Compose 相当:

// BAD
Modifier.graphicsLayer { scaleX = if (visible) 1f else 0f; scaleY = if (visible) 1f else 0f }

// GOOD
Modifier.graphicsLayer {
    scaleX = if (visible) 1f else 0.95f
    scaleY = if (visible) 1f else 0.95f
    alpha = if (visible) 1f else 0f
}
3. 出現時に ease-in を使わない

Ease-in は開始が遅くなります。出現する要素がもたつくと、壊れているように感じられます。

/* BAD */
.card-enter { animation: fadeIn 0.3s ease-in; }

/* GOOD */
.card-enter { animation: fadeIn 0.3s ease-out; }
/* OR spring via JS for natural feel */
4. UI 操作の応答時間は500msを超えないようにする

モーダル、ドロップダウン、ツールチップ、タブなど、ユーザーは待っています。ユーザーの時間を大切にしましょう。

// BAD
gsap.to(modal, { opacity: 1, y: 0, duration: 0.8 });

// GOOD
gsap.to(modal, { opacity: 1, y: 0, duration: 0.25, ease: "power2.out" });

SwiftUI:

// BAD
.animation(.easeInOut(duration: 0.8), value: state)

// GOOD
.animation(.spring(response: 0.25, dampingFraction: 0.85), value: state)

Compose:

// BAD
animateContentSize(animationSpec = tween(800))

// GOOD
animateContentSize(animationSpec = spring(stiffness = Spring.StiffnessMediumLow))
5. prefers-reduced-motion を必ず考慮する

これはアクセシビリティ要件であり、あればよいというものではありません。

// BAD
gsap.from('.hero-title', { opacity: 0, y: 40, duration: 0.6 });

// GOOD
const prefersReduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
if (!prefersReduced) {
  gsap.from('.hero-title', { opacity: 0, y: 40, duration: 0.6 });
}

SwiftUI/Compose に相当する機能については、上記のクロスプラットフォームの「動きを減らす」セクションを参照してください。


パフォーマンスチェックリスト

  • アニメーションには transform と opacity(コンポジットのみのプロパティ)だけを使用する
  • will-change は控えめに使用し、アニメーションの完了後に削除する
  • JS アニメーションでは、setTimeout/setInterval より requestAnimationFrame を優先する
  • スクロール駆動の場合:CSS の animation-timeline > JS の IntersectionObserver > スクロールリスナー
  • ローエンドデバイスでテストする(DevTools で CPU を4倍にスロットルする)

クイックリファレンス:サブスキルの読み込み

必要な内容読み込むファイル
イージングの詳細、スプリング設定references/easing-guide.md
コピーして使える入場/退出パターンreferences/enter-exit-recipes.md
デザイナー向けのスタイル選択references/designers.md
モバイル UX のコンテキスト../mobile-principles/SKILL.md
デスクトップ UX のコンテキスト../desktop-principles/SKILL.md
GSAP の詳細../gsap/SKILL.md
Framer Motion の詳細../framer-motion/SKILL.md
CSS のみのアニメーション../css-native/SKILL.md
Three.js/R3F../threejs-r3f/SKILL.md
Canvas/ジェネレーティブ../canvas-generative/SKILL.md
Compose の Android アニメーション../compose-motion/SKILL.md
Compose Multiplatform../compose-multiplatform/SKILL.md
SwiftUI の iOS/macOS アニメーション../swiftui-motion/SKILL.md
Compose の高度なグラフィックス../compose-graphics/SKILL.md
SwiftUI の高度なグラフィックス../swiftui-graphics/SKILL.md
ビジュアル/モーション/アクセシビリティの監査../design-audit/SKILL.md
UI/UX インテリジェンス(84種類のスタイル、192種類のパレット)../ui-ux-pro-max/SKILL.md

コメント