Motion
Motion for Vue offers a number of ways to animate your UI. Scaling from extremely simple prop-based animations, to more complex orchestration.
- Blazing-Fast Animations
- Effortless Animation Syntax
- Interactive Motion Support
- Dynamic Variant Control
- Scroll & View Animations
- TypeScript-Powered Precision
Installation
Install the component from your command line.
sh
$ npm add @oku-ui/motion
Animation
vue
<script setup lang="ts">
import { Motion } from '@oku-ui/motion'
</script>
<template>
<Motion
class="bg-white size-52 aspect-square rounded-2xl"
:initial="{ scale: 0 }"
:animate="{ rotate: 180, scale: 1 }"
:transition="{
type: 'spring',
stiffness: 260,
damping: 20,
delay: 0.3,
}"
/>
</template>
Variants
vue
<script setup lang="ts">
import { Motion } from '@oku-ui/motion'
const container = {
hidden: { opacity: 1, scale: 0 },
visible: {
opacity: 1,
scale: 1,
},
} as any
const items = {
hidden: { y: 20, opacity: 0, scale: 0.85 },
visible: {
y: 0,
opacity: 1,
},
} as any
const list = [0, 1, 2, 3, 4]
</script>
<template>
<Motion
as="ul"
:variants="container"
initial="hidden"
animate="visible"
:transition="{
duration: 0.3,
type: 'spring',
stiffness: 260,
damping: 20,
delay: 0.3,
}"
class="rounded-2xl overflow-hidden list-none p-2 grid-cols-2 grid-rows-2 aspect-square bg-white/20 size-60 grid"
>
<Motion
v-for="(item, i) in list"
:key="item"
:variants="items"
:transition="{
delay: 0.8 + i * 0.2,
}"
class="bg-white rounded-full origin-center"
/>
</Motion>
</template>
Keyframes
vue
<script setup lang="ts">
import { Motion } from '@oku-ui/motion'
</script>
<template>
<Motion
class="bg-white w-1/6 aspect-square rounded-2xl"
:animate="{
scale: [1, 2, 2, 1, 1],
rotate: [0, 0, 180, 180, 0],
borderRadius: ['0%', '0%', '50%', '50%', '0%'],
}"
:transition="{
duration: 2,
ease: 'easeInOut',
times: [0, 0.2, 0.5, 0.8, 1],
repeat: Infinity,
repeatDelay: 1,
}"
/>
</template>
Gesture
vue
<script setup lang="ts">
import { Motion } from '@oku-ui/motion'
</script>
<template>
<Motion
:hover="{ scale: 1.2, rotate: 90 }"
:press="{
scale: 0.8,
rotate: -90,
borderRadius: '100%',
}"
:transition="{
type: 'spring',
stiffness: 260,
damping: 20,
}"
as="button"
class="rounded-2xl overflow-hidden list-none p-2 grid-cols-2 grid-rows-2 aspect-square bg-white size-52 grid"
/>
</template>
InView
vue
<script setup lang="ts">
import { Motion } from '@oku-ui/motion'
</script>
<template>
<Motion
class="bg-white size-52 aspect-square rounded-2xl"
:initial="{ scale: 0 }"
:in-view="{ rotate: 180, scale: 1 }"
:in-view-options="{
once: true,
}"
:transition="{
type: 'spring',
stiffness: 260,
damping: 20,
delay: 0.3,
}"
/>
</template>
Path
vue
<script lang="ts" setup>
import { Motion } from '@oku-ui/motion'
const paths = [
'M167.269 135.905C147.041 121.058 125.439 97.3033 119.976 71.1281C119.564 76.9345 119.566 82.7541 120.605 88.7999C122.464 99.6408 126.617 109.923 132.439 119.198C138.399 128.693 146.045 136.66 154.346 144.067C162.15 151.029 169.497 158.175 171.164 169.019C179.723 171.086 187.705 175.11 193.876 181.816C200.073 188.548 203.225 196.896 203.162 205.366C206.217 197.979 207.497 190.012 205.176 180.625C200.122 160.193 183.221 147.613 167.269 135.905Z',
'M124.027 113.539C117.522 100.4 112.94 82.6316 115.856 67.201C110.818 81.588 109.076 97.0907 110.885 112.366C113.263 132.439 122.302 158.668 141.352 168.391C144.613 167.968 147.844 167.593 151.012 167.403C156.011 167.102 161.127 167.277 166.133 168.041C163.158 155.355 151.001 148.159 142.413 139.293C135.073 131.713 128.729 123.034 124.027 113.539Z',
'M98.7424 33.6512C95.7614 25.0337 90.8795 17.2208 84.7827 10.4845C84.1492 9.78471 83.4979 9.0658 82.8298 8.33331C83.511 9.38366 84.1707 10.4361 84.8042 11.4691C89.083 18.4353 92.654 25.902 94.9239 33.7896C99.4843 49.6365 96.9548 65.3786 93.7761 81.2128C90.1267 99.3734 87.3493 117.622 95.0866 135.197C101.609 150.014 113.648 160.627 128.58 165.517C115.139 152.77 108.317 131.936 106.085 114.4C104.848 104.682 104.956 94.8936 106.336 85.3153C105.716 67.8324 104.579 50.5116 98.7424 33.6512Z',
'M76.177 64.1946C70.7917 78.2659 64.8728 92.5604 63.9398 107.796C63.43 116.155 64.3825 124.762 67.5111 132.566C68.3747 134.723 69.427 136.719 70.5943 138.622C79.5335 147.358 86.7781 157.967 97.2948 164.754C106.542 170.72 116.898 171.095 127.376 170.119C99.3733 161.644 83.1981 132.963 85.5026 103.722C86.8628 86.4841 93.0961 69.8958 93.183 52.5181C93.2504 38.7693 88.6074 26.8535 82.0828 15.7164C82.968 18.5058 83.6559 21.3628 84.077 24.2881C86.0931 38.2864 81.161 51.1732 76.2512 64.0006L76.177 64.1946Z',
'M134.272 241.214C150.122 242.727 168.072 241.359 181.778 232.436C197.15 222.431 203.799 202.193 191.42 186.951C167.571 157.583 129.343 184.989 100.241 172.244C86.0378 166.023 78.0122 151.948 66.8728 141.859C59.0163 134.745 49.7647 129.616 39.8643 126.47C42.7956 127.996 45.6487 129.695 48.3891 131.621C58.322 138.592 65.2216 147.753 72.3253 157.469C81.2448 169.668 92.6944 177.691 107.678 180.11C120.423 182.171 134.713 180.083 146.668 185.769C154.924 189.697 161.5 199.143 158.185 208.557C154.824 218.095 143.537 223.189 134.431 224.928C110.38 229.524 88.5092 214.883 74.5362 196.253C65.1609 183.752 59.0098 169.532 52.2577 155.524C48.6776 148.093 44.2297 141.743 37.9723 136.388C36.4774 135.107 34.9217 133.917 33.3335 132.772C46.7076 148.698 52.748 170.849 61.3813 189.872C75.0417 219.972 101.727 238.107 134.272 241.214Z',
'M50.7257 138.6C45.4512 134.118 39.6017 130.566 33.3811 127.829C37.2063 130.327 40.8058 133.182 44.0365 136.245C52.6568 144.42 56.8747 155.114 61.9648 165.646C72.4119 187.25 86.5693 210.19 110.445 218.142C121.797 221.922 135.184 221.617 145.568 215.173C151.671 211.383 156.156 204.781 152.251 197.644C148.43 190.659 140.324 188.471 133.058 187.546C121.552 186.083 109.85 186.649 98.6283 183.237C89.3529 180.415 80.9303 175.001 74.4428 167.732C66.02 158.301 60.4872 146.891 50.7257 138.6Z',
'M188.339 234.039C195.316 239.918 206.779 235.489 211.604 228.492C216.736 221.056 214.937 211.147 208.515 205.367C206.115 212.065 202.298 218.363 197.61 223.758C195.073 227.77 191.919 231.175 188.339 234.039Z',
]
const icon = {
hidden: {
opacity: 0,
pathLength: 0,
fill: 'rgba(255, 255, 255, 0)',
},
visible: {
opacity: 1,
pathLength: 1,
fill: 'rgba(255, 255, 255, 1)',
},
}
</script>
<template>
<Motion
as="svg"
viewBox="0 0 250 250"
:style="{
strokeLinejoin: 'round',
strokeLinecap: 'round',
}"
class="rounded-2xl overflow-hidden stroke-white stroke-2 list-none p-4 grid-cols-2 grid-rows-2 aspect-square w-1/2 grid"
>
<Motion
as="svg"
viewBox="0 0 250 250"
:style="{
strokeLinejoin: 'round',
strokeLinecap: 'round',
}"
class="rounded-2xl overflow-hidden stroke-white stroke-2 list-none p-4 aspect-square w-1/2"
>
<Motion
v-for="(d, index) in paths"
:key="index"
as="path"
:d="d"
:variants="icon"
:initial="{
opacity: 0,
pathLength: 0,
fill: 'rgba(255, 255, 255, 0)',
}"
:animate="{
opacity: 1,
pathLength: 1,
fill: '#FFF',
stroke: '#FFF',
}"
:transition="{
duration: 2,
ease: 'easeInOut',
fill: {
duration: 2,
ease: [1, 0, 0.8, 1],
},
}"
/>
</Motion>
</Motion>
</template>