Keyframes
The core:keyframes plugin manages CSS @keyframes animations. It generates @keyframes rules as preflight CSS and provides autocomplete for animationName and animation properties.
How It Works
- Keyframe definitions are collected from
config.keyframes.keyframesduringrawConfigConfigured. - During
configureEngine, each definition is resolved and registered:- Autocomplete entries are added for
animationNameandanimation. - Entries with
framesare stored inengine.keyframes.store.
- Autocomplete entries are added for
- A preflight function scans atomic styles for animation references to determine which keyframes are actually used.
- Only used keyframes (or those with
pruneUnused: false) are emitted to CSS output.
Config
ts
interface KeyframesConfig {
/** Array of keyframe definitions. */
keyframes: Keyframes[]
/** Whether to prune unused keyframes from CSS output. @default true */
pruneUnused?: boolean
}Keyframe Definition Formats
PikaCSS supports three forms for defining keyframes:
1. String Form
Registers only the keyframe name for autocomplete — no @keyframes block is generated.
ts
'external-animation'2. Tuple Form
ts
type TupleForm = [name: string, frames?: KeyframesProgress, autocomplete?: string[], pruneUnused?: boolean]3. Object Form
ts
interface ObjectForm { name: string, frames?: KeyframesProgress, autocomplete?: string[], pruneUnused?: boolean }KeyframesProgress
The frames object maps animation stops to CSS properties:
from— alias for0%to— alias for100%`${number}%`— any percentage stop (e.g.,'25%','50%')
Full Example
ts
// pika.config.ts
import { defineEngineConfig } from '@pikacss/unplugin-pikacss'
export default defineEngineConfig({
keyframes: {
keyframes: [
// Tuple form: [name, frames, autocomplete?, pruneUnused?]
['fade-in', {
from: { opacity: '0' },
to: { opacity: '1' },
}, ['fade-in 0.3s ease']],
// Object form
{
name: 'slide-up',
frames: {
from: { transform: 'translateY(100%)' },
to: { transform: 'translateY(0)' },
},
autocomplete: ['slide-up 0.5s ease-out'],
pruneUnused: false, // always include in CSS output
},
// Percentage-based keyframes
['bounce', {
'0%': { transform: 'translateY(0)' },
'50%': { transform: 'translateY(-20px)' },
'100%': { transform: 'translateY(0)' },
}],
// String-only form: register an external animation name for autocomplete
'external-animation',
],
// Prune keyframes not referenced in atomic styles (default: true)
pruneUnused: true,
},
})Usage with pika()
Reference defined keyframes in animationName or the animation shorthand:
ts
const className = pika({
animation: 'fade-in 0.3s ease',
})Generated CSS output:
css
/* Preflight: @keyframes definitions */
@keyframes fade-in {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes slide-up {
from { transform: translateY(100%); }
to { transform: translateY(0); }
}
/* Atomic style generated by pika() */
.a { animation: fade-in 0.3s ease; }Pruning Unused Keyframes
By default, pruneUnused is true. Only keyframes whose names appear in animationName or animation atomic style values are included in CSS output.
- Global setting:
keyframes.pruneUnusedapplies to all entries. - Per-keyframe override: Set
pruneUnusedon an individual entry. - Entries without
framesare never output (they only affect autocomplete).
Autocomplete
The plugin registers these autocomplete values automatically:
animationName— the keyframe name (e.g.,fade-in)animation— the name followed by a space (e.g.,fade-in) to prompt for duration/easing- Custom
autocompletestrings are also added asanimationsuggestions
Engine API
Plugins can manage keyframes programmatically:
engine.keyframes.store—Map<string, ResolvedKeyframesConfig>of all registered keyframes with framesengine.keyframes.add(...list)— add keyframe definitions at runtime (accepts all three forms)
Source Reference
packages/core/src/internal/plugins/keyframes.ts
Next
- Continue to Selectors