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.

Open playground

Read the docs

Eighteen keys. Hover to feel them.

full gallery

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.

remix

fade + slide, expo settle

remix

elastic pop with overshoot

remix

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.

trigger reference

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.

extending vivace

Works where your markup lives

Attributes pass through every renderer, and dynamically mounted elements register

themselves. No wrapper components to import, ever.

HTML

Svelte

React

Vue

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.

community gallery

Try the playground

Browse the gallery