36
loading...
This website collects cookies to deliver better user experience
However, we don't always see such an organized system for stitching together consistent, meaningful animations.
Managing a design system without motion is enough work in and of itself.
Orchestrating motions is a unique skillset.
Without motion expertise, it's a bit easier to say what we don't want instead of what we do want.
Design specifications can be grouped by component. It's harder to generalize motion "groups" as it may vary depending on the context.
// motion.js
const types = {
entrance: 'entrance',
exit: 'exit',
effect: 'effect',
};
// motion.js
const types = {
entrance: 'entrance',
exit: 'exit',
effect: 'effect',
};
const durations = {
fast: 200,
slow: 250,
};
easeOut
is an easing function used primarily for entrance (the opposite of "out") animations.easeIn
is an easing function used primarily for exit (the opposite of "in") animations.easeInOut
is an easing function that animates most of the property in the middle of the timeline.// motion.js
const types = {
entrance: 'entrance',
exit: 'exit',
effect: 'effect',
};
const durations = {
fast: 200,
slow: 250,
};
const easings = {
effect: 'easeInOut',
entrance: 'easeOut',
exit: 'easeIn',
};
// motion.js
const types = {
entrance: 'entrance',
exit: 'exit',
effect: 'effect',
};
const durations = {
effect: 250,
entrance: 250,
exit: 250,
};
const easings = {
effect: 'easeInOut',
entrance: 'easeOut',
exit: 'easeIn',
};
const transitions = {
effect: {
duration: durations[types.effect],
ease: easings[types.effect],
},
entrance: {
duration: durations[types.entrance],
ease: easings[types.entrance],
},
exit: {
duration: durations[types.exit],
ease: easings[types.exit],
},
};
transition
type:// motion.js
const types = {
entrance: 'entrance',
exit: 'exit',
effect: 'effect',
};
const durations = {
effect: 250,
entrance: 250,
exit: 250,
};
const easings = {
effect: 'easeInOut',
entrance: 'easeOut',
exit: 'easeIn',
};
const transitions = {
effect: {
duration: durations[types.effect],
ease: easings[types.effect],
},
entrance: {
duration: durations[types.entrance],
ease: easings[types.entrance],
},
exit: {
duration: durations[types.exit],
ease: easings[types.exit],
},
};
const motions = {
move: { transition: transitions[types.effect] },
moveIn: { transition: transitions[types.entrance] },
moveOut: { transition: transitions[types.exit] },
// ...etc
};
// motion.js
import { motion, useAnimation } from 'framer-motion';
// ...
function toSeconds({ ms }) {
return ms / 1000;
}
function normalize(transition) {
return {
...transition,
duration: toSeconds({ ms: transition.duration }),
};
}
export function useMove(config = {}) {
const controls = useAnimation();
return {
motion,
animate: controls,
trigger: (animatedProperties = {}) => {
controls.start({
...animatedProperties,
transition: normalize(transitions.move),
});
},
};
};
// SomeComponent.jsx
import React, { useState } from 'react';
import { useMove } from '...';
const SomeComponent = () => {
const [isShifted, setIsShifted] = useState();
const { motion, animate, trigger } = useMove();
return (
<motion.div
animate={animate}
onClick={() => {
trigger({ x: isShifted ? 0 : 100 });
setIsShifted(!isShifted);
}}
>
Click me!
</motion.div>
);
};