Kreativní
Expert
Claude
Animace a micro-interactions design
Navrhni systém animací a micro-interactions pro aplikaci včetně timing a easing curves.
Prompt text
Délka: Dlouhý
Vytvoř animation system pro [APLIKACE/WEB]. Typ: [MOBILE/DESKTOP/WATCH]. Use case: [FITNESS/E-COMMERCE/SOCIAL/PRODUCTIVITY]. Struktura: 1) **Animation Principles** - purpose (proč animovat), duration guidelines (150ms fast, 300ms normal, 500ms slow), easing functions (ease-in, ease-out, spring), performance (60 FPS, GPU acceleration), 2) **Micro-interactions Categories** - feedback (button press, toggle), loading states (spinners, skeletons), transitions (page, modal), gestures (swipe, pinch), notifications (toast, badge), 3) **State Transitions** - hover effects, active states, disabled states, focus indicators, loading → success → error flows, 4) **Loading Animations** - skeleton screens (content placeholders), spinners (indeterminate progress), progress bars (determinate), pull-to-refresh, infinite scroll loaders, 5) **Gesture Animations** - swipe gestures (dismiss, navigate), pull gestures (refresh, more options), drag & drop, pinch to zoom, haptic feedback coordination, 6) **Page Transitions** - enter animations (fade, slide, scale), exit animations, shared element transitions, navigation stack animations, modal presentations, 7) **Success/Error States** - checkmark animations, error shake, success confetti/celebration, retry button appearance, 8) **Performance Optimization** - use CSS transforms (not top/left), will-change hints, reduce motion (respect prefers-reduced-motion), avoid layout thrashing, measure with Chrome DevTools, 9) **Motion Tokens** - duration.fast (150ms), easing.spring (cubic-bezier), delay values, stagger delays (for lists), 10) **Code Examples** - CSS keyframes, React Spring examples, Framer Motion, Lottie integration, Reanimated (React Native). Zahrň 10+ practical examples s code.
Příklad použití
Vstup:
Aplikace: Fitness tracking app "FitFlow". Typ: React Native mobile app. Use case: Tracking workouts, logging exercises, viewing progress charts.
Výstup:
# Animation & Micro-interactions System: FitFlow
## 1. Animation Principles
**Purpose (Why Animate?):**
1. **Feedback** - Confirm user actions (button pressed, workout saved)
2. **Guidance** - Direct attention (highlight next exercise)
3. **Context** - Show relationships (stats → graph transition)
4. **Delight** - Celebrate achievements (workout complete animation)
5. **Smoothness** - Reduce perceived loading time (skeleton screens)
**Duration Guidelines:**
```
Instant: 0-100ms (Hover feedback, highlight)
Fast: 150-200ms (Button press, toggle switch)
Normal: 300-400ms (Modal open, page transition)
Slow: 500-700ms (Complex transitions, celebrations)
Very Slow: 1000ms+ (Loading states, major achievements)
```
**Easing Functions:**
```css
/* Linear - Constant speed (rarely used) */
easing.linear: cubic-bezier(0, 0, 1, 1)
/* Ease-in - Slow start, fast end (exits) */
easing.easeIn: cubic-bezier(0.4, 0, 1, 1)
/* Ease-out - Fast start, slow end (entrances) */
easing.easeOut: cubic-bezier(0, 0, 0.2, 1)
/* Ease-in-out - Slow both ends (most common) */
easing.easeInOut: cubic-bezier(0.4, 0, 0.2, 1)
/* Spring - Bouncy, playful */
easing.spring: cubic-bezier(0.68, -0.55, 0.265, 1.55)
/* Material Design Standard */
easing.standard: cubic-bezier(0.4, 0.0, 0.2, 1)
```
**Performance Targets:**
- **60 FPS** (16.67ms per frame) - Smooth animations
- **GPU Acceleration** - Use `transform` and `opacity` properties only
- **Will-change** - Hint browser about upcoming animations
- **Measure with Chrome DevTools** - Check for dropped frames
**GPU-Friendly Properties:**
```css
✅ transform: translateX(), translateY(), scale(), rotate()
✅ opacity: 0-1
❌ Avoid: top, left, width, height, margin (cause layout reflow)
```
---
## 2. Micro-interactions Categories
### Feedback Interactions
**Button Press (Haptic + Visual)**
```typescript
// React Native with Reanimated
import { useAnimatedStyle, withSpring } from 'react-native-reanimated';
const onPressIn = () => {
scale.value = withSpring(0.95, { damping: 15 });
// Haptic feedback
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
};
const onPressOut = () => {
scale.value = withSpring(1, { damping: 15 });
};
const animatedStyle = useAnimatedStyle(() => ({
transform: [{ scale: scale.value }]
}));
```
**Toggle Switch**
```typescript
const switchAnimation = () => {
translateX.value = withTiming(isOn ? 20 : 0, {
duration: 200,
easing: Easing.ease
});
backgroundColor.value = withTiming(
isOn ? colors.brand.blue.500 : colors.gray.300,
{ duration: 200 }
);
};
```
### Loading States
**Skeleton Screen**
```typescript
// Shimmer effect
const shimmerAnimation = () => {
translateX.value = withRepeat(
withTiming(200, { duration: 1500, easing: Easing.ease }),
-1, // Infinite
false
);
};
return (
<View style={styles.skeleton}>
<Animated.View style={[styles.shimmer, animatedShimmerStyle]} />
</View>
);
```
**Spinner (Rotation)**
```css
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.spinner {
animation: spin 1s linear infinite;
}
```
### Transitions
**Modal Slide-Up**
```typescript
const modalAnimation = useAnimatedStyle(() => ({
transform: [
{
translateY: withSpring(isVisible ? 0 : screenHeight, {
damping: 20,
stiffness: 90
})
}
],
opacity: withTiming(isVisible ? 1 : 0, { duration: 200 })
}));
```
### Gesture Animations
**Swipe to Dismiss**
```typescript
import { GestureDetector, Gesture } from 'react-native-gesture-handler';
const panGesture = Gesture.Pan()
.onUpdate((e) => {
translateX.value = e.translationX;
opacity.value = 1 - Math.abs(e.translationX) / 300;
})
.onEnd((e) => {
if (Math.abs(e.translationX) > 100) {
// Dismiss
translateX.value = withTiming(300, { duration: 200 });
runOnJS(onDismiss)();
} else {
// Snap back
translateX.value = withSpring(0);
opacity.value = withSpring(1);
}
});
```
### Notifications
**Toast Slide-In**
```typescript
const toastAnimation = () => {
// Enter from top
translateY.value = withSequence(
withTiming(0, { duration: 300, easing: Easing.out(Easing.ease) }),
withDelay(2000, withTiming(-100, { duration: 300 })) // Auto-dismiss
);
};
```
---
## 3. State Transitions
### Hover Effects (Web)
```css
.workout-card {
transition: transform 150ms ease-out,
box-shadow 150ms ease-out;
}
.workout-card:hover {
transform: translateY(-4px);
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.15);
}
```
### Active States
```css
.button:active {
transform: scale(0.95);
transition: transform 50ms ease-out;
}
```
### Disabled States
```css
.button:disabled {
opacity: 0.5;
cursor: not-allowed;
transition: opacity 200ms ease;
}
```
### Focus Indicators
```css
.input:focus {
border-color: var(--color-primary);
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
transition: border-color 150ms ease,
box-shadow 150ms ease;
}
```
### Loading → Success → Error Flow
```typescript
const statusAnimation = (status: 'idle' | 'loading' | 'success' | 'error') => {
switch (status) {
case 'loading':
// Spinner rotation
rotation.value = withRepeat(
withTiming(360, { duration: 1000, easing: Easing.linear }),
-1
);
break;
case 'success':
// Checkmark scale + haptic
scale.value = withSequence(
withSpring(1.2, { damping: 10 }),
withSpring(1)
);
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success);
break;
case 'error':
// Shake + haptic
translateX.value = withSequence(
withTiming(-10, { duration: 50 }),
withTiming(10, { duration: 50 }),
withTiming(-10, { duration: 50 }),
withTiming(0, { duration: 50 })
);
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Error);
break;
}
};
```
---
## 4. Loading Animations
### Skeleton Screens
```typescript
const WorkoutSkeleton = () => (
<View style={styles.container}>
<ShimmerPlaceholder
width={100}
height={100}
borderRadius={8}
shimmerStyle={{ backgroundColor: '\1' }}
/>
<View style={styles.content}>
<ShimmerPlaceholder width={200} height={20} />
<ShimmerPlaceholder width={150} height={16} />
<ShimmerPlaceholder width={100} height={14} />
</View>
</View>
);
```
### Progress Bar (Determinate)
```typescript
const ProgressBar = ({ progress }) => {
const widthAnimation = useAnimatedStyle(() => ({
width: withTiming(`${progress}%`, { duration: 300 })
}));
return (
<View style={styles.progressContainer}>
<Animated.View style={[styles.progressFill, widthAnimation]} />
</View>
);
};
```
### Pull-to-Refresh
```typescript
const refreshAnimation = () => {
// Rotate refresh icon as user pulls
rotation.value = withTiming(pullDistance * 2, { duration: 0 });
if (pullDistance > threshold) {
// Trigger refresh
rotation.value = withRepeat(
withTiming(360, { duration: 800, easing: Easing.linear }),
-1
);
runOnJS(onRefresh)();
}
};
```
### Infinite Scroll Loader
```typescript
const InfiniteLoader = () => {
const dotAnimation = useSharedValue(0);
useEffect(() => {
dotAnimation.value = withRepeat(
withSequence(
withTiming(1, { duration: 400 }),
withTiming(0, { duration: 400 })
),
-1
);
}, []);
return (
<View style={styles.loaderContainer}>
<Animated.View style={[styles.dot, { opacity: dotAnimation }]} />
<Animated.View style={[styles.dot, { opacity: dotAnimation, animationDelay: '133ms' }]} />
<Animated.View style={[styles.dot, { opacity: dotAnimation, animationDelay: '266ms' }]} />
</View>
);
};
```
---
## 5. Gesture Animations
### Swipe to Navigate
```typescript
const swipeGesture = Gesture.Pan()
.onUpdate((e) => {
if (e.translationX > 0) {
// Swipe right = go back
translateX.value = Math.min(e.translationX, screenWidth);
}
})
.onEnd((e) => {
if (e.translationX > screenWidth * 0.5 && e.velocityX > 500) {
// Complete navigation
translateX.value = withTiming(screenWidth, { duration: 200 });
runOnJS(navigation.goBack)();
} else {
// Cancel, snap back
translateX.value = withSpring(0);
}
});
```
### Pull to Refresh
```typescript
const pullGesture = Gesture.Pan()
.onUpdate((e) => {
if (e.translationY > 0 && scrollY === 0) {
pullDistance.value = Math.min(e.translationY, 120);
refreshIconRotation.value = pullDistance.value * 3; // Rotate as pull
}
})
.onEnd(() => {
if (pullDistance.value > 80) {
// Trigger refresh
isRefreshing.value = true;
runOnJS(fetchData)();
// Animate to loading position
pullDistance.value = withTiming(60, { duration: 200 });
} else {
// Cancel
pullDistance.value = withSpring(0);
refreshIconRotation.value = withSpring(0);
}
});
```
### Drag & Drop
```typescript
const dragGesture = Gesture.Pan()
.onStart(() => {
// Lift up effect
scale.value = withSpring(1.1);
shadowOpacity.value = withTiming(0.3, { duration: 150 });
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium);
})
.onUpdate((e) => {
translateX.value = e.translationX;
translateY.value = e.translationY;
})
.onEnd(() => {
// Drop
scale.value = withSpring(1);
shadowOpacity.value = withTiming(0.1, { duration: 150 });
// Check drop zone
const isInDropZone = checkCollision(translateX.value, translateY.value);
if (isInDropZone) {
// Success
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success);
runOnJS(onDrop)();
} else {
// Snap back to origin
translateX.value = withSpring(0);
translateY.value = withSpring(0);
}
});
```
### Pinch to Zoom
```typescript
const pinchGesture = Gesture.Pinch()
.onUpdate((e) => {
scale.value = Math.max(1, Math.min(e.scale, 3)); // Clamp 1x-3x
})
.onEnd(() => {
if (scale.value < 1.2) {
// Snap back to 1x
scale.value = withSpring(1);
}
});
const doubleTapGesture = Gesture.Tap()
.numberOfTaps(2)
.onEnd(() => {
// Toggle 1x <-> 2x
scale.value = withSpring(scale.value > 1 ? 1 : 2);
});
```
### Haptic Feedback Coordination
```typescript
const hapticFeedback = {
light: () => Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light),
medium: () => Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium),
heavy: () => Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Heavy),
success: () => Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success),
warning: () => Haptics.notificationAsync(Haptics.NotificationFeedbackType.Warning),
error: () => Haptics.notificationAsync(Haptics.NotificationFeedbackType.Error)
};
// Usage
onPress={() => {
hapticFeedback.light();
// Animate button
}};
```
---
## 6. Page Transitions
### Fade Transition
```typescript
const FadeTransition = ({ children, isVisible }) => {
const opacity = useSharedValue(0);
useEffect(() => {
opacity.value = withTiming(isVisible ? 1 : 0, { duration: 300 });
}, [isVisible]);
const animatedStyle = useAnimatedStyle(() => ({
opacity: opacity.value
}));
return <Animated.View style={animatedStyle}>{children}</Animated.View>;
};
```
### Slide Transition
```typescript
const SlideTransition = ({ children, direction = 'right' }) => {
const translateX = useSharedValue(direction === 'right' ? screenWidth : -screenWidth);
useEffect(() => {
translateX.value = withSpring(0, { damping: 20 });
}, []);
return (
<Animated.View style={{ transform: [{ translateX }] }}>
{children}
</Animated.View>
);
};
```
### Shared Element Transition
```typescript
import { SharedElement } from 'react-navigation-shared-element';
// List screen
<SharedElement id={`workout.${workoutId}.image`}>
<Image source={workout.image} />
</SharedElement>
// Detail screen
<SharedElement id={`workout.${workoutId}.image`}>
<Image source={workout.image} style={styles.heroImage} />
</SharedElement>
// Navigation config
WorkoutDetailScreen.sharedElements = (route) => [
{ id: `workout.${route.params.workoutId}.image`, animation: 'move' }
];
```
### Modal Presentation
```typescript
const ModalTransition = ({ isVisible, children }) => {
const translateY = useSharedValue(screenHeight);
const backdropOpacity = useSharedValue(0);
useEffect(() => {
if (isVisible) {
backdropOpacity.value = withTiming(0.5, { duration: 200 });
translateY.value = withSpring(0, { damping: 20, stiffness: 100 });
} else {
backdropOpacity.value = withTiming(0, { duration: 200 });
translateY.value = withTiming(screenHeight, { duration: 300 });
}
}, [isVisible]);
return (
<>
<Animated.View style={[styles.backdrop, { opacity: backdropOpacity }]} />
<Animated.View style={[styles.modal, { transform: [{ translateY }] }]}>
{children}
</Animated.View>
</>
);
};
```
---
## 7. Success/Error States
### Checkmark Animation
```typescript
const CheckmarkAnimation = () => {
const scale = useSharedValue(0);
const rotation = useSharedValue(-45);
useEffect(() => {
scale.value = withSequence(
withTiming(0, { duration: 0 }),
withDelay(200, withSpring(1, { damping: 10 }))
);
rotation.value = withSequence(
withTiming(-45, { duration: 0 }),
withDelay(200, withSpring(0, { damping: 12 }))
);
}, []);
return (
<Animated.View style={[styles.checkmark, { transform: [{ scale }, { rotate: `${rotation}deg` }] }]}>
<Icon name=\"check\" size={32} color=\"#10B981\" />
</Animated.View>
);
};
```
### Error Shake
```typescript
const errorShake = () => {
translateX.value = withSequence(
withTiming(-10, { duration: 50 }),
withTiming(10, { duration: 50 }),
withTiming(-10, { duration: 50 }),
withTiming(10, { duration: 50 }),
withTiming(0, { duration: 50 })
);
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Error);
};
```
### Success Confetti
```typescript
import LottieView from 'lottie-react-native';
const SuccessConfetti = () => (
<LottieView
source={require('./confetti.json')}
autoPlay
loop={false}
style={styles.confetti}
onAnimationFinish={() => {
// Clean up
}}
/>
);
```
### Retry Button Appearance
```typescript
const retryAnimation = () => {
// Fade in + bounce
opacity.value = withTiming(1, { duration: 200 });
scale.value = withSequence(
withSpring(1.1, { damping: 10 }),
withSpring(1)
);
};
```
---
## 8. Performance Optimization
### Use CSS Transforms (Not Top/Left)
```css
/* ❌ Slow - Causes layout reflow */
.element {
position: absolute;
left: 100px;
transition: left 300ms;
}
/* ✅ Fast - GPU accelerated */
.element {
transform: translateX(100px);
transition: transform 300ms;
}
```
### Will-Change Hints
```css
.animated-element {
will-change: transform, opacity;
}
/* Remove after animation */
.animated-element.done {
will-change: auto;
}
```
### Respect prefers-reduced-motion
```css
@media (prefers-reduced-motion: reduce) {
* {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
```
```typescript
// React Native
import { AccessibilityInfo } from 'react-native';
const [reduceMotion, setReduceMotion] = useState(false);
useEffect(() => {
AccessibilityInfo.isReduceMotionEnabled().then(setReduceMotion);
}, []);
const duration = reduceMotion ? 0 : 300;
```
### Avoid Layout Thrashing
```javascript
// ❌ Bad - Forces multiple layouts
for (let i = 0; i < 100; i++) {
const height = element.offsetHeight; // Read
element.style.height = height + 10; // Write
}
// ✅ Good - Batch reads and writes
const heights = [];
for (let i = 0; i < 100; i++) {
heights.push(elements[i].offsetHeight); // Read all
}
for (let i = 0; i < 100; i++) {
elements[i].style.height = heights[i] + 10; // Write all
}
```
### Measure with Chrome DevTools
1. Open DevTools → Performance tab
2. Record animation
3. Check for:
- **Dropped frames** (red bars)
- **Long tasks** (>50ms)
- **Excessive repaints** (green bars)
---
## 9. Motion Tokens
```json
{
"duration": {
"instant": "0ms",
"fast": "150ms",
"normal": "300ms",
"slow": "500ms",
"slower": "700ms"
},
"easing": {
"linear": "cubic-bezier(0, 0, 1, 1)",
"easeIn": "cubic-bezier(0.4, 0, 1, 1)",
"easeOut": "cubic-bezier(0, 0, 0.2, 1)",
"easeInOut": "cubic-bezier(0.4, 0, 0.2, 1)",
"spring": "cubic-bezier(0.68, -0.55, 0.265, 1.55)"
},
"delay": {
"none": "0ms",
"short": "100ms",
"medium": "200ms",
"long": "500ms"
},
"stagger": {
"list": "50ms", // Per item in list
"card": "100ms" // Per card in grid
}
}
```
**Usage:**
```typescript
import { motionTokens } from '@/design-tokens';
const fadeIn = withTiming(1, {
duration: motionTokens.duration.normal,
easing: Easing.bezier(...motionTokens.easing.easeOut)
});
```
---
## 10. Code Examples
### CSS Keyframes
```css
@keyframes slideInUp {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.workout-card {
animation: slideInUp 300ms ease-out;
}
/* Stagger children */
.workout-list .workout-card:nth-child(1) { animation-delay: 0ms; }
.workout-list .workout-card:nth-child(2) { animation-delay: 50ms; }
.workout-list .workout-card:nth-child(3) { animation-delay: 100ms; }
```
### React Spring
```typescript
import { useSpring, animated } from 'react-spring';
const FadeIn = ({ children }) => {
const props = useSpring({
from: { opacity: 0, transform: 'translateY(20px)' },
to: { opacity: 1, transform: 'translateY(0px)' },
config: { tension: 280, friction: 60 }
});
return <animated.div style={props}>{children}</animated.div>;
};
```
### Framer Motion
```typescript
import { motion } from 'framer-motion';
const WorkoutCard = () => (
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -20 }}
transition={{ duration: 0.3, ease: 'easeOut' }}
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
>
<WorkoutContent />
</motion.div>
);
```
### Lottie Integration
```typescript
import LottieView from 'lottie-react-native';
const WorkoutCompleteAnimation = () => (
<LottieView
source={require('./workout-complete.json')}
autoPlay
loop={false}
style={{ width: 200, height: 200 }}
onAnimationFinish={() => {
navigation.navigate('Summary');
}}
/>
);
```
### Reanimated (React Native)
```typescript
import Animated, {
useSharedValue,
useAnimatedStyle,
withSpring,
withTiming
} from 'react-native-reanimated';
const WorkoutButton = () => {
const scale = useSharedValue(1);
const opacity = useSharedValue(1);
const animatedStyle = useAnimatedStyle(() => ({
transform: [{ scale: scale.value }],
opacity: opacity.value
}));
const onPressIn = () => {
scale.value = withSpring(0.95);
};
const onPressOut = () => {
scale.value = withSpring(1);
};
const onPress = async () => {
// Success animation
scale.value = withSequence(
withSpring(1.1),
withSpring(1)
);
await delay(300);
// Fade out
opacity.value = withTiming(0, { duration: 200 });
};
return (
<Animated.View style={animatedStyle}>
<TouchableOpacity
onPressIn={onPressIn}
onPressOut={onPressOut}
onPress={onPress}
>
<Text>Start Workout</Text>
</TouchableOpacity>
</Animated.View>
);
};
```
---
**Animation System Version:** 1.0
**Platform:** React Native (iOS/Android) + React Web
**Last Updated:** Nov 2025
**Performance Target:** 60 FPS
## 1. Animation Principles
**Purpose (Why Animate?):**
1. **Feedback** - Confirm user actions (button pressed, workout saved)
2. **Guidance** - Direct attention (highlight next exercise)
3. **Context** - Show relationships (stats → graph transition)
4. **Delight** - Celebrate achievements (workout complete animation)
5. **Smoothness** - Reduce perceived loading time (skeleton screens)
**Duration Guidelines:**
```
Instant: 0-100ms (Hover feedback, highlight)
Fast: 150-200ms (Button press, toggle switch)
Normal: 300-400ms (Modal open, page transition)
Slow: 500-700ms (Complex transitions, celebrations)
Very Slow: 1000ms+ (Loading states, major achievements)
```
**Easing Functions:**
```css
/* Linear - Constant speed (rarely used) */
easing.linear: cubic-bezier(0, 0, 1, 1)
/* Ease-in - Slow start, fast end (exits) */
easing.easeIn: cubic-bezier(0.4, 0, 1, 1)
/* Ease-out - Fast start, slow end (entrances) */
easing.easeOut: cubic-bezier(0, 0, 0.2, 1)
/* Ease-in-out - Slow both ends (most common) */
easing.easeInOut: cubic-bezier(0.4, 0, 0.2, 1)
/* Spring - Bouncy, playful */
easing.spring: cubic-bezier(0.68, -0.55, 0.265, 1.55)
/* Material Design Standard */
easing.standard: cubic-bezier(0.4, 0.0, 0.2, 1)
```
**Performance Targets:**
- **60 FPS** (16.67ms per frame) - Smooth animations
- **GPU Acceleration** - Use `transform` and `opacity` properties only
- **Will-change** - Hint browser about upcoming animations
- **Measure with Chrome DevTools** - Check for dropped frames
**GPU-Friendly Properties:**
```css
✅ transform: translateX(), translateY(), scale(), rotate()
✅ opacity: 0-1
❌ Avoid: top, left, width, height, margin (cause layout reflow)
```
---
## 2. Micro-interactions Categories
### Feedback Interactions
**Button Press (Haptic + Visual)**
```typescript
// React Native with Reanimated
import { useAnimatedStyle, withSpring } from 'react-native-reanimated';
const onPressIn = () => {
scale.value = withSpring(0.95, { damping: 15 });
// Haptic feedback
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
};
const onPressOut = () => {
scale.value = withSpring(1, { damping: 15 });
};
const animatedStyle = useAnimatedStyle(() => ({
transform: [{ scale: scale.value }]
}));
```
**Toggle Switch**
```typescript
const switchAnimation = () => {
translateX.value = withTiming(isOn ? 20 : 0, {
duration: 200,
easing: Easing.ease
});
backgroundColor.value = withTiming(
isOn ? colors.brand.blue.500 : colors.gray.300,
{ duration: 200 }
);
};
```
### Loading States
**Skeleton Screen**
```typescript
// Shimmer effect
const shimmerAnimation = () => {
translateX.value = withRepeat(
withTiming(200, { duration: 1500, easing: Easing.ease }),
-1, // Infinite
false
);
};
return (
<View style={styles.skeleton}>
<Animated.View style={[styles.shimmer, animatedShimmerStyle]} />
</View>
);
```
**Spinner (Rotation)**
```css
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.spinner {
animation: spin 1s linear infinite;
}
```
### Transitions
**Modal Slide-Up**
```typescript
const modalAnimation = useAnimatedStyle(() => ({
transform: [
{
translateY: withSpring(isVisible ? 0 : screenHeight, {
damping: 20,
stiffness: 90
})
}
],
opacity: withTiming(isVisible ? 1 : 0, { duration: 200 })
}));
```
### Gesture Animations
**Swipe to Dismiss**
```typescript
import { GestureDetector, Gesture } from 'react-native-gesture-handler';
const panGesture = Gesture.Pan()
.onUpdate((e) => {
translateX.value = e.translationX;
opacity.value = 1 - Math.abs(e.translationX) / 300;
})
.onEnd((e) => {
if (Math.abs(e.translationX) > 100) {
// Dismiss
translateX.value = withTiming(300, { duration: 200 });
runOnJS(onDismiss)();
} else {
// Snap back
translateX.value = withSpring(0);
opacity.value = withSpring(1);
}
});
```
### Notifications
**Toast Slide-In**
```typescript
const toastAnimation = () => {
// Enter from top
translateY.value = withSequence(
withTiming(0, { duration: 300, easing: Easing.out(Easing.ease) }),
withDelay(2000, withTiming(-100, { duration: 300 })) // Auto-dismiss
);
};
```
---
## 3. State Transitions
### Hover Effects (Web)
```css
.workout-card {
transition: transform 150ms ease-out,
box-shadow 150ms ease-out;
}
.workout-card:hover {
transform: translateY(-4px);
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.15);
}
```
### Active States
```css
.button:active {
transform: scale(0.95);
transition: transform 50ms ease-out;
}
```
### Disabled States
```css
.button:disabled {
opacity: 0.5;
cursor: not-allowed;
transition: opacity 200ms ease;
}
```
### Focus Indicators
```css
.input:focus {
border-color: var(--color-primary);
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
transition: border-color 150ms ease,
box-shadow 150ms ease;
}
```
### Loading → Success → Error Flow
```typescript
const statusAnimation = (status: 'idle' | 'loading' | 'success' | 'error') => {
switch (status) {
case 'loading':
// Spinner rotation
rotation.value = withRepeat(
withTiming(360, { duration: 1000, easing: Easing.linear }),
-1
);
break;
case 'success':
// Checkmark scale + haptic
scale.value = withSequence(
withSpring(1.2, { damping: 10 }),
withSpring(1)
);
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success);
break;
case 'error':
// Shake + haptic
translateX.value = withSequence(
withTiming(-10, { duration: 50 }),
withTiming(10, { duration: 50 }),
withTiming(-10, { duration: 50 }),
withTiming(0, { duration: 50 })
);
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Error);
break;
}
};
```
---
## 4. Loading Animations
### Skeleton Screens
```typescript
const WorkoutSkeleton = () => (
<View style={styles.container}>
<ShimmerPlaceholder
width={100}
height={100}
borderRadius={8}
shimmerStyle={{ backgroundColor: '\1' }}
/>
<View style={styles.content}>
<ShimmerPlaceholder width={200} height={20} />
<ShimmerPlaceholder width={150} height={16} />
<ShimmerPlaceholder width={100} height={14} />
</View>
</View>
);
```
### Progress Bar (Determinate)
```typescript
const ProgressBar = ({ progress }) => {
const widthAnimation = useAnimatedStyle(() => ({
width: withTiming(`${progress}%`, { duration: 300 })
}));
return (
<View style={styles.progressContainer}>
<Animated.View style={[styles.progressFill, widthAnimation]} />
</View>
);
};
```
### Pull-to-Refresh
```typescript
const refreshAnimation = () => {
// Rotate refresh icon as user pulls
rotation.value = withTiming(pullDistance * 2, { duration: 0 });
if (pullDistance > threshold) {
// Trigger refresh
rotation.value = withRepeat(
withTiming(360, { duration: 800, easing: Easing.linear }),
-1
);
runOnJS(onRefresh)();
}
};
```
### Infinite Scroll Loader
```typescript
const InfiniteLoader = () => {
const dotAnimation = useSharedValue(0);
useEffect(() => {
dotAnimation.value = withRepeat(
withSequence(
withTiming(1, { duration: 400 }),
withTiming(0, { duration: 400 })
),
-1
);
}, []);
return (
<View style={styles.loaderContainer}>
<Animated.View style={[styles.dot, { opacity: dotAnimation }]} />
<Animated.View style={[styles.dot, { opacity: dotAnimation, animationDelay: '133ms' }]} />
<Animated.View style={[styles.dot, { opacity: dotAnimation, animationDelay: '266ms' }]} />
</View>
);
};
```
---
## 5. Gesture Animations
### Swipe to Navigate
```typescript
const swipeGesture = Gesture.Pan()
.onUpdate((e) => {
if (e.translationX > 0) {
// Swipe right = go back
translateX.value = Math.min(e.translationX, screenWidth);
}
})
.onEnd((e) => {
if (e.translationX > screenWidth * 0.5 && e.velocityX > 500) {
// Complete navigation
translateX.value = withTiming(screenWidth, { duration: 200 });
runOnJS(navigation.goBack)();
} else {
// Cancel, snap back
translateX.value = withSpring(0);
}
});
```
### Pull to Refresh
```typescript
const pullGesture = Gesture.Pan()
.onUpdate((e) => {
if (e.translationY > 0 && scrollY === 0) {
pullDistance.value = Math.min(e.translationY, 120);
refreshIconRotation.value = pullDistance.value * 3; // Rotate as pull
}
})
.onEnd(() => {
if (pullDistance.value > 80) {
// Trigger refresh
isRefreshing.value = true;
runOnJS(fetchData)();
// Animate to loading position
pullDistance.value = withTiming(60, { duration: 200 });
} else {
// Cancel
pullDistance.value = withSpring(0);
refreshIconRotation.value = withSpring(0);
}
});
```
### Drag & Drop
```typescript
const dragGesture = Gesture.Pan()
.onStart(() => {
// Lift up effect
scale.value = withSpring(1.1);
shadowOpacity.value = withTiming(0.3, { duration: 150 });
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium);
})
.onUpdate((e) => {
translateX.value = e.translationX;
translateY.value = e.translationY;
})
.onEnd(() => {
// Drop
scale.value = withSpring(1);
shadowOpacity.value = withTiming(0.1, { duration: 150 });
// Check drop zone
const isInDropZone = checkCollision(translateX.value, translateY.value);
if (isInDropZone) {
// Success
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success);
runOnJS(onDrop)();
} else {
// Snap back to origin
translateX.value = withSpring(0);
translateY.value = withSpring(0);
}
});
```
### Pinch to Zoom
```typescript
const pinchGesture = Gesture.Pinch()
.onUpdate((e) => {
scale.value = Math.max(1, Math.min(e.scale, 3)); // Clamp 1x-3x
})
.onEnd(() => {
if (scale.value < 1.2) {
// Snap back to 1x
scale.value = withSpring(1);
}
});
const doubleTapGesture = Gesture.Tap()
.numberOfTaps(2)
.onEnd(() => {
// Toggle 1x <-> 2x
scale.value = withSpring(scale.value > 1 ? 1 : 2);
});
```
### Haptic Feedback Coordination
```typescript
const hapticFeedback = {
light: () => Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light),
medium: () => Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium),
heavy: () => Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Heavy),
success: () => Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success),
warning: () => Haptics.notificationAsync(Haptics.NotificationFeedbackType.Warning),
error: () => Haptics.notificationAsync(Haptics.NotificationFeedbackType.Error)
};
// Usage
onPress={() => {
hapticFeedback.light();
// Animate button
}};
```
---
## 6. Page Transitions
### Fade Transition
```typescript
const FadeTransition = ({ children, isVisible }) => {
const opacity = useSharedValue(0);
useEffect(() => {
opacity.value = withTiming(isVisible ? 1 : 0, { duration: 300 });
}, [isVisible]);
const animatedStyle = useAnimatedStyle(() => ({
opacity: opacity.value
}));
return <Animated.View style={animatedStyle}>{children}</Animated.View>;
};
```
### Slide Transition
```typescript
const SlideTransition = ({ children, direction = 'right' }) => {
const translateX = useSharedValue(direction === 'right' ? screenWidth : -screenWidth);
useEffect(() => {
translateX.value = withSpring(0, { damping: 20 });
}, []);
return (
<Animated.View style={{ transform: [{ translateX }] }}>
{children}
</Animated.View>
);
};
```
### Shared Element Transition
```typescript
import { SharedElement } from 'react-navigation-shared-element';
// List screen
<SharedElement id={`workout.${workoutId}.image`}>
<Image source={workout.image} />
</SharedElement>
// Detail screen
<SharedElement id={`workout.${workoutId}.image`}>
<Image source={workout.image} style={styles.heroImage} />
</SharedElement>
// Navigation config
WorkoutDetailScreen.sharedElements = (route) => [
{ id: `workout.${route.params.workoutId}.image`, animation: 'move' }
];
```
### Modal Presentation
```typescript
const ModalTransition = ({ isVisible, children }) => {
const translateY = useSharedValue(screenHeight);
const backdropOpacity = useSharedValue(0);
useEffect(() => {
if (isVisible) {
backdropOpacity.value = withTiming(0.5, { duration: 200 });
translateY.value = withSpring(0, { damping: 20, stiffness: 100 });
} else {
backdropOpacity.value = withTiming(0, { duration: 200 });
translateY.value = withTiming(screenHeight, { duration: 300 });
}
}, [isVisible]);
return (
<>
<Animated.View style={[styles.backdrop, { opacity: backdropOpacity }]} />
<Animated.View style={[styles.modal, { transform: [{ translateY }] }]}>
{children}
</Animated.View>
</>
);
};
```
---
## 7. Success/Error States
### Checkmark Animation
```typescript
const CheckmarkAnimation = () => {
const scale = useSharedValue(0);
const rotation = useSharedValue(-45);
useEffect(() => {
scale.value = withSequence(
withTiming(0, { duration: 0 }),
withDelay(200, withSpring(1, { damping: 10 }))
);
rotation.value = withSequence(
withTiming(-45, { duration: 0 }),
withDelay(200, withSpring(0, { damping: 12 }))
);
}, []);
return (
<Animated.View style={[styles.checkmark, { transform: [{ scale }, { rotate: `${rotation}deg` }] }]}>
<Icon name=\"check\" size={32} color=\"#10B981\" />
</Animated.View>
);
};
```
### Error Shake
```typescript
const errorShake = () => {
translateX.value = withSequence(
withTiming(-10, { duration: 50 }),
withTiming(10, { duration: 50 }),
withTiming(-10, { duration: 50 }),
withTiming(10, { duration: 50 }),
withTiming(0, { duration: 50 })
);
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Error);
};
```
### Success Confetti
```typescript
import LottieView from 'lottie-react-native';
const SuccessConfetti = () => (
<LottieView
source={require('./confetti.json')}
autoPlay
loop={false}
style={styles.confetti}
onAnimationFinish={() => {
// Clean up
}}
/>
);
```
### Retry Button Appearance
```typescript
const retryAnimation = () => {
// Fade in + bounce
opacity.value = withTiming(1, { duration: 200 });
scale.value = withSequence(
withSpring(1.1, { damping: 10 }),
withSpring(1)
);
};
```
---
## 8. Performance Optimization
### Use CSS Transforms (Not Top/Left)
```css
/* ❌ Slow - Causes layout reflow */
.element {
position: absolute;
left: 100px;
transition: left 300ms;
}
/* ✅ Fast - GPU accelerated */
.element {
transform: translateX(100px);
transition: transform 300ms;
}
```
### Will-Change Hints
```css
.animated-element {
will-change: transform, opacity;
}
/* Remove after animation */
.animated-element.done {
will-change: auto;
}
```
### Respect prefers-reduced-motion
```css
@media (prefers-reduced-motion: reduce) {
* {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
```
```typescript
// React Native
import { AccessibilityInfo } from 'react-native';
const [reduceMotion, setReduceMotion] = useState(false);
useEffect(() => {
AccessibilityInfo.isReduceMotionEnabled().then(setReduceMotion);
}, []);
const duration = reduceMotion ? 0 : 300;
```
### Avoid Layout Thrashing
```javascript
// ❌ Bad - Forces multiple layouts
for (let i = 0; i < 100; i++) {
const height = element.offsetHeight; // Read
element.style.height = height + 10; // Write
}
// ✅ Good - Batch reads and writes
const heights = [];
for (let i = 0; i < 100; i++) {
heights.push(elements[i].offsetHeight); // Read all
}
for (let i = 0; i < 100; i++) {
elements[i].style.height = heights[i] + 10; // Write all
}
```
### Measure with Chrome DevTools
1. Open DevTools → Performance tab
2. Record animation
3. Check for:
- **Dropped frames** (red bars)
- **Long tasks** (>50ms)
- **Excessive repaints** (green bars)
---
## 9. Motion Tokens
```json
{
"duration": {
"instant": "0ms",
"fast": "150ms",
"normal": "300ms",
"slow": "500ms",
"slower": "700ms"
},
"easing": {
"linear": "cubic-bezier(0, 0, 1, 1)",
"easeIn": "cubic-bezier(0.4, 0, 1, 1)",
"easeOut": "cubic-bezier(0, 0, 0.2, 1)",
"easeInOut": "cubic-bezier(0.4, 0, 0.2, 1)",
"spring": "cubic-bezier(0.68, -0.55, 0.265, 1.55)"
},
"delay": {
"none": "0ms",
"short": "100ms",
"medium": "200ms",
"long": "500ms"
},
"stagger": {
"list": "50ms", // Per item in list
"card": "100ms" // Per card in grid
}
}
```
**Usage:**
```typescript
import { motionTokens } from '@/design-tokens';
const fadeIn = withTiming(1, {
duration: motionTokens.duration.normal,
easing: Easing.bezier(...motionTokens.easing.easeOut)
});
```
---
## 10. Code Examples
### CSS Keyframes
```css
@keyframes slideInUp {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.workout-card {
animation: slideInUp 300ms ease-out;
}
/* Stagger children */
.workout-list .workout-card:nth-child(1) { animation-delay: 0ms; }
.workout-list .workout-card:nth-child(2) { animation-delay: 50ms; }
.workout-list .workout-card:nth-child(3) { animation-delay: 100ms; }
```
### React Spring
```typescript
import { useSpring, animated } from 'react-spring';
const FadeIn = ({ children }) => {
const props = useSpring({
from: { opacity: 0, transform: 'translateY(20px)' },
to: { opacity: 1, transform: 'translateY(0px)' },
config: { tension: 280, friction: 60 }
});
return <animated.div style={props}>{children}</animated.div>;
};
```
### Framer Motion
```typescript
import { motion } from 'framer-motion';
const WorkoutCard = () => (
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -20 }}
transition={{ duration: 0.3, ease: 'easeOut' }}
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
>
<WorkoutContent />
</motion.div>
);
```
### Lottie Integration
```typescript
import LottieView from 'lottie-react-native';
const WorkoutCompleteAnimation = () => (
<LottieView
source={require('./workout-complete.json')}
autoPlay
loop={false}
style={{ width: 200, height: 200 }}
onAnimationFinish={() => {
navigation.navigate('Summary');
}}
/>
);
```
### Reanimated (React Native)
```typescript
import Animated, {
useSharedValue,
useAnimatedStyle,
withSpring,
withTiming
} from 'react-native-reanimated';
const WorkoutButton = () => {
const scale = useSharedValue(1);
const opacity = useSharedValue(1);
const animatedStyle = useAnimatedStyle(() => ({
transform: [{ scale: scale.value }],
opacity: opacity.value
}));
const onPressIn = () => {
scale.value = withSpring(0.95);
};
const onPressOut = () => {
scale.value = withSpring(1);
};
const onPress = async () => {
// Success animation
scale.value = withSequence(
withSpring(1.1),
withSpring(1)
);
await delay(300);
// Fade out
opacity.value = withTiming(0, { duration: 200 });
};
return (
<Animated.View style={animatedStyle}>
<TouchableOpacity
onPressIn={onPressIn}
onPressOut={onPressOut}
onPress={onPress}
>
<Text>Start Workout</Text>
</TouchableOpacity>
</Animated.View>
);
};
```
---
**Animation System Version:** 1.0
**Platform:** React Native (iOS/Android) + React Web
**Last Updated:** Nov 2025
**Performance Target:** 60 FPS
Kde použít tento prompt?
Najděte vhodné AI nástroje pro použití tohoto promptu a maximalizujte jeho efektivitu.
Podobné prompty
Accessibility audit a WCAG compliance
Proveď komplexní accessibility audit s WCAG 2.1 compliance checklist a remediation plán.
Kreativní
Zobrazit
Animační principy pro UI micro-interactions
Navrhni micro-interakce s přesnými timing, easing funkcemi a animačními principy pro UI element.
Kreativní
Zobrazit
Architektonická vizualizace - exteriér i interiér
Vytvoř fotorealistickou architektonickou vizualizaci s precizní specifikací osvětlení, materiálů a atmosféry.
Kreativní
Zobrazit
Art style replication - "in style of..."
Nauč se replikovat specifické art styly od malířů, umělců nebo art movements.
Kreativní
Zobrazit
Objevte další AI prompty
Prozkoumejte naši sbírku Kreativní promptů a najděte ty, které vám pomohou dosáhnout lepších výsledků.