CSS keyframe animations for anything in JavaScript. Parse @keyframes, animate any object or DOM element.
npm run build # library → dist/keyframes.js + keyframes.cjs + keyframes.d.ts
npm run gh-pages # demo (cube) → dist/
npm run dev # vite dev server on :8080 (cube demo)
npm test # vitest (jsdom)
npm run bench # vitest benchsrc/
├── animation/ # Animation engine (see animation/CLAUDE.md)
│ ├── index.ts # Animation, CSSKeyframesAnimation classes
│ ├── group.ts # AnimationGroup — multi-animation compositor
│ ├── numeric.ts # NumericAnimation — keyframe interp over {key: number} objects
│ ├── smooth.ts # SmoothProgress — exponential smoothing for progress values
│ ├── morph.ts # ElementMorph — position/scale interp between DOM elements
│ ├── timeline.ts # Timeline (abstract), ScrollTimeline, ManualTimeline
│ ├── animations.ts # 30+ preset animations (fadeIn, bounce, etc.)
│ ├── constants.ts # Types, defaults (AnimationOptions, Vars, etc.)
│ ├── utils.ts # Frame calc, value interpolation, timing
│ └── waapi.ts # Web Animations API delegation
├── parsing/ # CSS @keyframes parsing (see parsing/CLAUDE.md)
│ ├── keyframes.ts # @keyframes grammar via parse-that combinators
│ ├── format.ts # Animation → CSS string serialization (Prettier)
│ ├── units.ts # Re-export: CSSColor, CSSValueUnit, parseCSSColor, parseCSSValueUnit from value.js
│ ├── utils.ts # Re-export: parser combinators from value.js
│ └── index.ts # Barrel
├── units/ # Value types & normalization (see units/CLAUDE.md)
│ ├── index.ts # Re-export: ValueUnit, FunctionValue, ValueArray
│ ├── constants.ts # Re-export: unit sets (LENGTH_UNITS, etc.)
│ ├── utils.ts # Re-export: conversion fns (convertToPixels, etc.)
│ ├── normalize.ts # LOCAL: DOM-aware unit normalization + memoization
│ └── color/ # Color space classes, normalization, conversion
│ ├── index.ts # Re-export: Color, RGBColor, OKLABColor, etc.
│ ├── constants.ts # Re-export: color ranges, white points, matrices
│ ├── normalize.ts # Re-export: normalizeColorUnits, normalizeColor, normalizeColorUnit, normalizeColorUnitComponent, colorUnit2
│ ├── utils.ts # Re-export: ~60 color space converters/utilities
│ └── colorFilter.ts # Re-export: rgb2ColorFilter
├── easing.ts # Re-export barrel: easing fns from value.js
├── math.ts # Re-export barrel: clamp, lerp, bezier from value.js
├── utils.ts # Re-export barrel + local memoizeDecorator
└── env.d.ts # Vue *.vue module declaration
demo/ # Vue 3 demo apps (see demo/CLAUDE.md)
├── @/ # Shared: editor shell, composables, UI (shadcn-vue), styles
├── cube/ # 3D cube + AnimationGroup + matrix editor
├── simple/ # Minimal: single animation + controls
├── square/ # Custom transform function demo
├── amiga/ # 3D animated sphere (Three.js)
├── playground/ # Asset playground: drag-and-drop viewport with preset animation binding
├── balls/ # Vanilla JS: CSS vars + staggered anim
├── boxes/ # Vanilla JS: matrix3d transforms
└── bench/ # Performance benchmark suite
test/ # Vitest (jsdom) — 15 files, 261 tests
├── animation.test.ts # Animation options, setters, frame creation
├── easing.test.ts # Easing functions, bezier, stepped
├── editor-parsing.test.ts # Complex CSS parsing, editor integration
├── equivalence.test.ts # Animation equivalence across input types
├── format.test.ts # CSS formatting, normalization
├── group.test.ts # AnimationGroup orchestration
├── morph.test.ts # ElementMorph position/scale interpolation
├── numeric.test.ts # NumericAnimation keyframe interpolation
├── parsing.test.ts # CSS time/percent/keyframes parsing
├── performance.test.ts # Perf benchmarks, memory
├── presets.test.ts # Preset animation library
├── sharing.test.ts # State cloning, reuse
├── smooth.test.ts # SmoothProgress exponential smoothing
├── timeline.test.ts # Timeline, ScrollTimeline, ManualTimeline
└── units.test.ts # Unit conversions, color parsing, interpolation
bench/ # Vitest bench — 3 files
├── interpolation.bench.ts
├── parser.bench.ts
└── playwright.bench.ts
src/animation/index.ts — builds to dist/keyframes.js (ESM) + dist/keyframes.cjs (CJS) + dist/keyframes.d.ts.
Primary exports: Animation, CSSKeyframesAnimation, AnimationGroup, NumericAnimation, SmoothProgress, ElementMorph, Timeline, ScrollTimeline, ManualTimeline, getAnimationId.
| Package | Role |
|---|---|
@mkbabb/value.js |
ValueUnit, Color, math, easing, parsing, normalization |
@mkbabb/parse-that |
Parser combinators for @keyframes grammar |
Most of src/ is thin re-export barrels over value.js. Local logic lives in:
src/animation/— the animation engine itselfsrc/parsing/keyframes.ts+format.ts— @keyframes grammar + serializationsrc/units/normalize.ts— DOM-aware computed value resolution
- TypeScript
strict: true,verbatimModuleSyntax: true,exactOptionalPropertyTypes: true moduleResolution: bundler,target: ES2022import typefor type-only imports- Path aliases:
@src/,@components/,@composables/,@styles/,@utils/,@assets/ - Memoization via
memoize()(from value.js) and localmemoizeDecorator - All exported parsing functions are memoized
- Prettier: 4-space indent, 80-char width, plugins: tailwind, organize-imports, classnames, merge
- Node >=22
- Frame pipeline:
addFrame()→parse()(reconcile vars, compute times) →AnimationFrame[]withinterpVars - Playback modes: rAF-based (default), WAAPI (opt-in for compositor-thread), managed (AnimationGroup controls)
- Interpolation dispatch: numeric →
lerp; color → perceptual (oklabdefault); computed units (vh,calc,var) → DOM resolution - Layer blending (AnimationGroup):
replace(z-order),add(accumulate),weighted(lerp by weight) - WAAPI eligibility: requires DOM targets, uniform timing, no computed units, no custom transforms, no color interpolation
- General primitives:
NumericAnimation(zero-alloc keyframe interp),SmoothProgress(exponential smoothing),ElementMorph(rect-to-rect transform),Timeline(progress driver) - Timeline pipeline:
sample() → clamp → easing → boundary snap → smoothing → progress. No rAF ownership — caller drives the loop. - ScrollTimeline: injectable
getScrollY/getViewportHeightcallbacks for testing without DOM - ManualTimeline: smoothing off by default; set raw value, get immediate result