Animate with attributes. Nothing else.
Compose entrances, springs and staggers directly in your markup. A tiny engine handles when — scroll, hover, click, focus — and pure CSS handles how.
$ bun add vivace-css "@pr-i_child-ascend_ease-out-back @fd @sc-i!"Eighteen keys. Hover to feel them.
full galleryTwo steps. No wrappers, no keyframes.
Initialize once
One call at your app's root. A MutationObserver keeps watching, so anything your framework mounts later registers itself.
import Vivace from 'vivace-css'
import 'vivace-css/vivace.css'
Vivace.init()Write attributes
Keys (@) say what plays, modifiers (_) tune it, data-viv-on says when. Everything composes.
<ul data-viv="@fd_child-ascend @sl-y" data-viv-on="appearing">
<li>Every list item</li>
<li>slides up in</li>
<li>sequence. That's it.</li>
</ul>- Every list item
- slides up in
- sequence. That's it.
Small grammar, endless compositions
Keys stack in one attribute; modifiers concatenate onto the key they tune. Click a card to replay it, or open it in the playground.
Real triggers, zero listeners per element
load, appearing, hover, click and focus — one shared IntersectionObserver and a handful of delegated
listeners for the whole page, no matter how many elements animate.
Beyond entrances
Exit animations that resolve as promises, bubbling lifecycle events
(vivace:play, vivace:end), and a plugin API for your own
keys and triggers — at runtime or as SCSS plugins.
// exits that wait for themselves
await Vivace.out(toast) // plays data-viv-out, resolves when done
toast.remove() // fill-mode kept it hidden — no flash
// your own keys and triggers
Vivace.defineKey('@wb', { keyframe: 10, vars: { '--ARZ1': '8deg' } })
Vivace.defineTrigger('longpress', (el, fire) => { /* … */ })Works where your markup lives
Attributes pass through every renderer, and dynamically mounted elements register themselves. No wrapper components to import, ever.
Compose one in ten seconds
Chain tokens in the playground, watch it live on real page sections, copy the attribute out — or ship it to the community gallery.