Compared with Nuxt modules
This page compares nanime with AnimeJS on its own and with
@hypernym/nuxt-anime, as of September 2026. If something is out of
date, open an issue.
For Vue packages, see
Compared with Vue packages.
How do the Nuxt modules compare?
nanime | @hypernym/nuxt-anime | |
|---|---|---|
| AnimeJS version | v4 | v3 |
| Latest release | Sep 2026 | Sep 2023 |
| Auto-imports | Yes | Opt-in |
| Safe during SSR, cleans up on unmount | Yes | Manual |
Rebuilds when a ref changes | Yes | No |
| Keeps the playhead on rebuild | Yes | No |
| Animate, timeline, SVG helpers | Yes | Yes |
| WAAPI, draggable, text, scroll, layout and more | Yes | No |
| Transition components | Yes | No |
@hypernym/nuxt-anime
provides the AnimeJS v3 anime function as $anime. With
composables: true, it also auto-imports it as useAnime. AnimeJS v4
split anime() into functions like animate() and createTimeline(), so
v3 code needs changes to run on v4.
nuxt-animejs is a Nuxt 2
module built on a v-anime directive. Its README says it is no longer
maintained.
Which should you pick?
nanimefor a Nuxt app on AnimeJS v4, especially one that animates lists or values that change.- AnimeJS on its own for one or two animations that never change.
@hypernym/nuxt-animefor an app that stays on AnimeJS v3.- A package from Compared with Vue packages for a Vue app without Nuxt.
How does a staggered entrance compare?
The three versions below do the same thing. Four cards fade up one after another on mount, and a Replay button plays the entrance again:
<script setup lang="ts">
import { stagger } from '#nanime/utils'
const cards = useTemplateRef('cards')
const entrance = useAnimate(cards, {
translateY: [16, 0],
opacity: [0, 1],
delay: stagger(80),
})
</script>
<template>
<button @click="entrance.restart()">Replay</button>
<div v-for="n in 4" :key="n" ref="cards" class="card" />
</template>
<script setup lang="ts">
import { animate } from 'animejs/animation'
import { stagger } from 'animejs/utils'
import type { JSAnimation } from 'animejs'
const cards = useTemplateRef('cards')
let entrance: JSAnimation | undefined
onMounted(() => {
if (!cards.value) return
entrance = animate(cards.value, {
translateY: [16, 0],
opacity: [0, 1],
delay: stagger(80),
})
})
onBeforeUnmount(() => entrance?.revert())
</script>
<template>
<button @click="entrance?.restart()">Replay</button>
<div v-for="n in 4" :key="n" ref="cards" class="card" />
</template>
<script setup lang="ts">
import type { AnimeInstance } from 'animejs'
const { $anime } = useNuxtApp()
const cards = useTemplateRef('cards')
let entrance: AnimeInstance | undefined
onMounted(() => {
if (!cards.value) return
entrance = $anime({
targets: cards.value,
translateY: [16, 0],
opacity: [0, 1],
delay: $anime.stagger(80),
})
})
onBeforeUnmount(() => cards.value && $anime.remove(cards.value))
</script>
<template>
<button @click="entrance?.restart()">Replay</button>
<div v-for="n in 4" :key="n" ref="cards" class="card" />
</template>
useAnimate waits for the cards to mount and
reverts the animation on unmount. entrance is the AnimeJS animation, so
methods like restart() work as the AnimeJS docs describe.
How do lists animate in and out?
<AnimeTransitionGroup> animates items
that enter and leave a v-for list. AnimeJS
layout slides the other items to their
new places. The three versions below scale items in and out:
- 1
- 2
- 3
- 4
- 5
<script setup lang="ts">
const items = ref([1, 2, 3, 4, 5])
</script>
<template>
<AnimeTransitionGroup
tag="ul"
enter-animation="scale"
leave-animation="scale"
class="relative"
>
<li v-for="item in items" :key="item">{{ item }}</li>
</AnimeTransitionGroup>
</template>
<script setup lang="ts">
import { animate } from 'animejs/animation'
const items = ref([1, 2, 3, 4, 5])
function onEnter(el: Element, done: () => void) {
animate(el, {
opacity: [0, 1],
scale: [0.85, 1],
duration: 300,
ease: 'out(3)',
onComplete: done,
})
}
function onLeave(el: Element, done: () => void) {
animate(el, {
opacity: 0,
scale: 0.85,
duration: 200,
ease: 'in(3)',
onComplete: done,
})
}
</script>
<template>
<TransitionGroup tag="ul" :css="false" @enter="onEnter" @leave="onLeave">
<li v-for="item in items" :key="item">{{ item }}</li>
</TransitionGroup>
</template>
<script setup lang="ts">
const { $anime } = useNuxtApp()
const items = ref([1, 2, 3, 4, 5])
function onEnter(el: Element, done: () => void) {
$anime({
targets: el,
opacity: [0, 1],
scale: [0.85, 1],
duration: 300,
easing: 'easeOutCubic',
complete: done,
})
}
function onLeave(el: Element, done: () => void) {
$anime({
targets: el,
opacity: 0,
scale: 0.85,
duration: 200,
easing: 'easeInCubic',
complete: done,
})
}
</script>
<template>
<TransitionGroup tag="ul" :css="false" @enter="onEnter" @leave="onLeave">
<li v-for="item in items" :key="item">{{ item }}</li>
</TransitionGroup>
</template>
The AnimeJS and @hypernym/nuxt-anime versions use Vue's
<TransitionGroup> with :css="false".
Vue animates moves only through a CSS move class, so the other items jump
to their new places.