Skip to content

Motion

Motion in Synchronicity is inspired by breath—organic, rhythmic, and calming. Animations should feel natural, never jarring or rushed.

“Movement follows stillness; stillness follows movement.”

Our motion system embodies three principles:

  1. Purposeful - Every animation serves a function
  2. Organic - Movements feel natural, not mechanical
  3. Contemplative - Timing encourages mindfulness
instant100msMicro-interactions, toggles
fast200msButton feedback, hover states
normal300msStandard transitions
slow500msPage transitions, modals
slower700msComplex reveals, emphasis
slowest1000msMeditative transitions

The signature animation pattern of Synchronicity follows human breathing:

const breathing = {
inhale: 3600, // 3.6 seconds - building, gathering
hold: 1200, // 1.2 seconds - stillness, peak
exhale: 4800, // 4.8 seconds - release, calm
total: 9600, // Complete cycle
};

This 9.6-second cycle creates a meditative rhythm suitable for:

  • Loading states
  • Background animations
  • Ambient UI elements
  • Transition sequences
const easing = {
linear: 'linear',
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)',
// Contemplative easings
gentleIn: 'cubic-bezier(0.25, 0.1, 0.25, 1)',
gentleOut: 'cubic-bezier(0.25, 0.1, 0.25, 1)',
breath: 'cubic-bezier(0.45, 0, 0.55, 1)',
};

For more organic, physics-based animations:

const spring = {
gentle: {
damping: 20,
stiffness: 100,
mass: 1,
},
bouncy: {
damping: 10,
stiffness: 150,
mass: 0.8,
},
stiff: {
damping: 30,
stiffness: 300,
mass: 0.5,
},
slow: {
damping: 25,
stiffness: 80,
mass: 1.2,
},
};

For elements appearing on screen:

import { useTheme } from '@synchronicity/react-native';
import Animated, {
useAnimatedStyle,
withTiming
} from 'react-native-reanimated';
function FadeIn({ children }) {
const { motion } = useTheme();
const style = useAnimatedStyle(() => ({
opacity: withTiming(1, {
duration: motion.duration.normal,
easing: motion.easing.easeOut,
}),
}));
return (
<Animated.View style={[{ opacity: 0 }, style]}>
{children}
</Animated.View>
);
}

For cards and modals:

const scaleIn = {
from: {
opacity: 0,
transform: [{ scale: 0.95 }],
},
to: {
opacity: 1,
transform: [{ scale: 1 }],
},
config: {
duration: 300,
easing: 'easeOut',
},
};

For meditative loading states:

function BreathingPulse() {
const { motion } = useTheme();
const opacity = useSharedValue(0.4);
useEffect(() => {
opacity.value = withRepeat(
withSequence(
// Inhale
withTiming(1, { duration: motion.breathing.inhale }),
// Hold
withDelay(motion.breathing.hold, withTiming(1, { duration: 0 })),
// Exhale
withTiming(0.4, { duration: motion.breathing.exhale })
),
-1, // Infinite
false
);
}, []);
return (
<Animated.View style={{ opacity }}>
{/* Content */}
</Animated.View>
);
}
  • Use easeOut for elements entering the screen
  • Use easeIn for elements leaving the screen
  • Use spring for gesture-driven animations
  • Use breathing rhythm for ambient, continuous animations
  • Keep UI feedback animations under 300ms
  • Use linear easing for UI transitions (feels mechanical)
  • Make users wait through long animations
  • Animate multiple things at once without choreography
  • Use bouncy springs for serious/contemplative contexts

Always respect user preferences for reduced motion:

import { useReducedMotion } from 'react-native-reanimated';
function AnimatedComponent() {
const reducedMotion = useReducedMotion();
const { motion } = useTheme();
const duration = reducedMotion ? 0 : motion.duration.normal;
// Use duration in animations
}
export const motion = {
duration: {
instant: 100,
fast: 200,
normal: 300,
slow: 500,
slower: 700,
slowest: 1000,
},
breathing: {
inhale: 3600,
hold: 1200,
exhale: 4800,
total: 9600,
},
easing: {
linear: 'linear',
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)',
breath: 'cubic-bezier(0.45, 0, 0.55, 1)',
},
spring: {
gentle: { damping: 20, stiffness: 100, mass: 1 },
bouncy: { damping: 10, stiffness: 150, mass: 0.8 },
stiff: { damping: 30, stiffness: 300, mass: 0.5 },
slow: { damping: 25, stiffness: 80, mass: 1.2 },
},
};