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.
Eighteen keys. Hover to feel them.
Two 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.
Write attributes
Keys (@) say what plays, modifiers (_) tune it, data-viv-on says when. Everything composes.
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.
fade + slide, expo settle
elastic pop with overshoot
flies in from deep Z, folding
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.
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.