Theme

Add keyframes and Tailwind-style animation strings through extendedTheme.

VinicuncaTheme is UnoCSS preset-wind4 Theme. extendedTheme takes a VinicuncaExtends object, which has only two fields: keyframes and a string-form animation map.

import type { CSSObject } from 'unocss';

interface VinicuncaExtends {
  keyframes?: Record<string, Record<string, CSSObject>>;
  animation?: Record<string, string>;
}

The preset merges these two fields into the UnoCSS theme. Keyframes become theme.animation.keyframes. Animation strings are parsed into durations, timingFns, and counts.

The preset reads no other fields from extendedTheme. Put colors, spacing, and other tokens on the UnoCSS theme option in defineConfig.

Use extendedTheme, not UnoCSS theme.animation alone, when you want this string format. Do not reuse built-in names such as spin unless you intend to replace them.

Keyframes and animation

Each keyframe name maps to a record of stop → CSS object (the same shape as a CSS @keyframes body, not CSSKeyframesRule).

Each animation value is a space-separated list:

[name] [duration] [timing-function] [iteration-count]

uno.config.ts
import { presetVinicunca } from '@vinicunca/unocss-preset';
import { defineConfig } from 'unocss';

export default defineConfig({
  presets: [
    presetVinicunca({
      extendedTheme: {
        keyframes: {
          wiggle: {
            '0%, 100%': { transform: 'rotate(-3deg)' },
            '50%': { transform: 'rotate(3deg)' }
          }
        },
        animation: {
          wiggle: 'wiggle 1s linear infinite'
        }
      }
    })
  ]
});

That yields animate-wiggle with duration 1s, timing linear, and iteration infinite.

If the map key differs from the keyframe name, animate-{key} becomes an alias. It reuses the keyframes of {name}, including built-in ones such as spin:

animation: {
  wiggle: 'wiggle 1s linear infinite',
  shake: 'wiggle 500ms ease-in-out 2'
}

animate-shake then runs the wiggle keyframes with its own duration, timing, and count. animate-wiggle keeps 1s linear infinite. The keyframes are emitted under the alias name, so the CSS is animation: shake 500ms ease-in-out 2 with @keyframes shake.

Placeholders

You can skip or blank a slot instead of omitting later values:

  • * — do not inject that property into the UnoCSS theme
  • + — inject the property, but with an empty string
extendedTheme: {
  animation: {
    foo: 'foo 1s * 3',
    bar: 'bar 1s +'
  }
}

foo keeps duration 1s and count 3, and skips the timing function. bar keeps duration 1s and injects an empty timing function.

Duration also accepts CSS variables (var(--duration)). This docs hub uses the same API for accordion, collapsible, and toast keyframes in its uno.config.ts.