本文へ移動
cccskills
無料GitHub で公開

motion-principles

Motion design foundation - timing, easing, enter/exit patterns, accessibility, performance.

インストール方法を見る

含まれるファイル(4)

  • SKILL.md8.9 KB
  • references/designers.md5.5 KB
  • references/easing-guide.md7.5 KB
  • references/enter-exit-recipes.md10.7 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

Version-sensitive. Every API name, SDK gate and browser-support claim below was verified on 2026-09-08 against primary sources. What against, and when, is in _jutsu/VERSIONS.md. If that date is old, re-verify before acting on a version number.

Motion Principles

The foundation. Loaded by every creative skill invocation. Concise rules here. Deep-dive in references/.


Timing Rules

ContextDurationWhy
Micro-interaction (toggle, hover, focus)100-150msInstant feedback, no perceived delay
UI transition (modal, drawer, tab switch)200-300msSmooth but never sluggish
Page/route transition300-500msEstablishes spatial narrative
Scroll-driven / 3DFree (progress-based)Tied to user input, no fixed duration

Frequency rule: The more often an animation plays, the shorter and subtler it must be. A button hover (1000x/day) = 100ms opacity. An onboarding reveal (1x ever) = 600ms+ full choreography.


Easing Cheat Sheet

ActionEasingWhy
Element entersease-out / springDecelerates into resting position (natural arrival)
Element exitsease-inAccelerates away (gets out of the way)
Element moves between statesease-in-outSmooth start and stop
Scroll-syncedlinear / noneMatches 1:1 with input, no lag perception
Bouncy/playfulspring (underdamped)Overshoot creates life
Snappy UIcubic-bezier(0.2, 0, 0, 1)Fast start, smooth land

Exit is always more subtle than enter. Enter: 300ms ease-out, full choreography. Exit: 200ms ease-in, opacity only.

Native easing equivalents (cross-platform)

Web (CSS / JS)SwiftUICompose
cubic-bezier(0.2, 0, 0, 1).spring(response: 0.4, dampingFraction: 0.85) or .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)
spring (bouncy).bouncy (iOS 17+)spring(stiffness = Spring.StiffnessLow, dampingRatio = Spring.DampingRatioMediumBouncy)
spring (smooth).smooth (iOS 17+)spring(stiffness = Spring.StiffnessMedium, dampingRatio = Spring.DampingRatioNoBouncy)

Accessibility (Non-Negotiable)

Reduced motion - MANDATORY

Every animated component must respect the user's reduced-motion preference. No exceptions, regardless of platform.

PlatformAPI
Web CSS@media (prefers-reduced-motion: reduce)
Web JSwindow.matchMedia('(prefers-reduced-motion: reduce)')
SwiftUI@Environment(\.accessibilityReduceMotion) var reduceMotion
UIKitUIAccessibility.isReduceMotionEnabled (+ reduceMotionStatusDidChangeNotification)
ComposeCustom helper using Settings.Global.ANIMATOR_DURATION_SCALE (deep-dive in 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)
    )
}

Other a11y requirements

  • Focus indicators must never be hidden by animations
  • Animated content must meet WCAG contrast ratios at every frame (no mid-transition fading to invisible text)
  • Looping animations: provide a pause mechanism

Universal "Do Not" Rules

1. Never animate width/height/top/left

Triggers layout recalculation every frame = jank.

/* 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 equivalent (BAD vs 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 equivalent (BAD vs 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. Never scale to 0

scale(0) causes elements to vanish in a black hole. Always keep a minimum.

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

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

SwiftUI equivalent:

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

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

Compose equivalent:

// 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. Never ease-in on an entry

Ease-in = slow start. An entering element that hesitates feels broken.

/* 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. Never exceed 500ms on a UI interaction

Modals, dropdowns, tooltips, tabs -- users are waiting. Respect their time.

// 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. Never skip prefers-reduced-motion

This is an accessibility requirement, not a nice-to-have.

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

See the cross-platform Reduced Motion section above for SwiftUI / Compose equivalents.


Performance Checklist

  • Only animate transform and opacity (composite-only properties)
  • Use will-change sparingly and remove it after animation completes
  • Prefer requestAnimationFrame over setTimeout/setInterval for JS animations
  • For scroll-driven: CSS animation-timeline > JS IntersectionObserver > scroll listeners
  • Test on low-end devices (throttle CPU 4x in DevTools)

Quick Reference: Loading Sub-skills

NeedLoad
Easing deep-dive, spring configsreferences/easing-guide.md
Copy-paste enter/exit patternsreferences/enter-exit-recipes.md
Designer-weighted style choicereferences/designers.md
Mobile UX context../mobile-principles/SKILL.md
Desktop UX context../desktop-principles/SKILL.md
GSAP specifics../gsap/SKILL.md
Framer Motion specifics../framer-motion/SKILL.md
CSS-only animations../css-native/SKILL.md
Three.js / R3F../threejs-r3f/SKILL.md
Canvas / generative../canvas-generative/SKILL.md
Compose Android animations../compose-motion/SKILL.md
Compose Multiplatform../compose-multiplatform/SKILL.md
SwiftUI iOS/macOS animations../swiftui-motion/SKILL.md
Compose advanced graphics../compose-graphics/SKILL.md
SwiftUI advanced graphics../swiftui-graphics/SKILL.md
Visual / motion / a11y audit../design-audit/SKILL.md
UI/UX intelligence (84 styles, 192 palettes)../ui-ux-pro-max/SKILL.md

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

bunshin

無料

Summon shadow clones: genjutsu's full-scale pipeline for a whole website or web app, from scratch or as a full redesign. Harvests the client's real material, researches in parallel, lets Impeccable lead the direction and genjutsu the motion, builds the pages with parallel agents, then loops fixes, verdicts and a cold-eyes art director until only minor issues remain, the round cap of the chosen tier is reached, or a round fixes nothing. Announces its cost first and asks twice. Web. Needs a host that can spawn subagents.

日本語の概要は準備中です。原文の説明を表示しています。

AThevon/genjutsu4542026年10月6日 更新

Algorithmic and generative art with Canvas 2D - particles, flow fields, noise, fractals, L-systems.

日本語の概要は準備中です。原文の説明を表示しています。

AThevon/genjutsu4542026年10月6日 更新

cast

無料

Cast genjutsu on a UI - creative coding for motion, micro-interactions, and wow-factor. Scans the stack, proposes an interaction thesis, loads the right sub-skills, implements the illusion. Adapts to Web, Android (Compose), Apple (SwiftUI).

日本語の概要は準備中です。原文の説明を表示しています。

AThevon/genjutsu4542026年10月6日 更新

Advanced Compose visuals - Material 3 Expressive motion physics, AGSL shaders (Android 13+), Canvas/DrawScope generative, graphicsLayer effects.

日本語の概要は準備中です。原文の説明を表示しています。

AThevon/genjutsu4542026年10月6日 更新

Jetpack Compose animation foundations - animate*AsState, AnimatedVisibility, Crossfade, updateTransition, SharedTransitionLayout, gestures.

日本語の概要は準備中です。原文の説明を表示しています。

AThevon/genjutsu4542026年10月6日 更新

Compose Multiplatform / KMP patterns - expect/actual composables, platform-specific code, density and font handling cross-target, iOS/Android/Desktop interop.

日本語の概要は準備中です。原文の説明を表示しています。

AThevon/genjutsu4542026年10月6日 更新

AThevon のスキルをすべて見る

このスキルの問題を報告する