CLI tool
jeremyckahn/rekapi avatar
jeremyckahn/rekapi

Rekapi: keyframe animation for JavaScript with no renderer attached

A keyframe animation library for JavaScript

659 stars71 forksJavaScriptMIT

At a glance

What is it?
Rekapi lets you define animations as keyframe timelines and control their playback, while leaving the drawing to a renderer, with DOM and canvas renderers bundled. That separation is the whole design, and it is also what makes the library usable outside a browser.
Who is it for?
Rekapi fits a project that wants a timeline of keyframes driving several visual targets at once, or that animates something the bundled renderers do not cover and can supply a renderer of its own. It is the wrong choice for a simple fade or a CSS transition, where the platform already does the job with less code.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The library draws nothing itself

The README states the design in one line: Rekapi is renderer-agnostic, and at its core it does not perform any rendering. It does expose an API for defining renderers, and comes bundled with renderers for the HTML DOM and the HTML5 2D `<canvas>`.

That is the structural decision everything else follows from. The library models a timeline of keyframes and the state of playback over that timeline, and a renderer is the thing that takes the current computed state and puts pixels on a screen. A DOM renderer and a canvas renderer therefore consume the same timeline and differ only in what they do with it.

The feature list names the two halves of the API: defining keyframe-based animations, and controlling animation playback. So there is an authoring side, where you say what changes and when, and a runtime side, where you start, stop, seek or loop a track.

For a reader coming from CSS transitions or the browser's own animation APIs, the difference in approach is that the animation is a data structure you build and then hand to something. That structure is what you can inspect, serialise, and drive from a single clock, which is the sort of thing a design tool or a storyboard system needs and a stylesheet does not.

Two bundled renderers, and an API for writing a third

The bundled renderers cover the two environments a browser-based animation most often needs: the HTML DOM and the HTML5 2D canvas.

Having both matters more than it might look. A single animation in a typical interface is a mixture: a panel that slides in is DOM, a chart or a progress ring drawn in a canvas is not, and a designer would want them to share a timeline rather than be hand-synchronised. With one timeline and two renderers, that coordination is a matter of pointing both at the same animation.

For anything else, the extension point is the renderer API the README mentions. That is the part of the design that generalises beyond the browser, because a renderer only has to know how to read the current state of the animation and apply it to whatever it draws. A renderer for SVG attributes, for a canvas library, for a native view or for a server-side rasteriser is a new implementation of an existing contract, not a new animation system.

The documentation site linked in the repository homepage is where the renderer contract is described, and the doc build in the project scripts is generated from the source, so the API reference is produced by the same toolchain that builds the library.

One npm install, then load it however you like

Installation is a single command:

code
npm install --save rekapi

Rekapi exposes a UMD module, so it can be loaded in whichever way suits the project. With ES6 modules:

javascript
// ES6
import { Rekapi, Actor } from 'rekapi';

With AMD:

javascript
// AMD
define(['rekapi'], rekapi => { });

Or with CommonJS:

javascript
// CommonJS
const rekapi = require('rekapi');

The named exports in the ES6 example are worth pausing on, because they are the vocabulary of the whole library. Rekapi is the animation container and Actor is the thing that plays a track, which is the pattern that lets one animation drive several targets, each an actor with its own progress through the same timeline.

The browser support statement sits in the README as well, and it is narrow on purpose: Rekapi officially supports Evergreen browsers. That is a commitment to a moving target rather than to a version list, and it is worth noting for anyone deploying to a controlled environment with a frozen browser, since the project does not publish a policy for that case.

The development loop is a set of npm scripts

The contribution workflow is documented as a list of npm scripts, and it is short enough to take in at a glance. Dependencies are installed with `npm install`:

code
npm install

The distributable `dist/rekapi.js` is generated with:

code
npm run build

and the tests run in the CLI with:

code
npm test

Documentation is generated into `dist/doc` with `npm run doc`, and there is a combined command that generates it, live-updates it and serves it in the browser, `npm run doc:live`. The development server is started with `npm start`.

Once the server is running, the README gives the two URLs to visit, the tests at http://localhost:9010/test/ and the documentation at http://localhost:9010/dist/doc/. Running the tests in a browser as well as in the command line is the point of that arrangement, since a library that animates DOM elements has to be tested against a real DOM, and the package pulls in jsdom for the command line side.

The package manifest fills in the rest of the tooling. The build is Vite, the test runner is Vitest with c8 for coverage, linting is JSHint over src, and the documentation is JSDoc with a configuration in the .jsdoc directory. The `deploy` script builds the library and the docs and publishes them to the gh-pages branch, and `preversion` runs lint and the tests before a version bump.

Three runtime dependencies, and a sorted index for keyframes

The runtime dependency list is short: `global`, `lodash.sortedindexby` and `shifty`. Two of those tell you something about the design.

`lodash.sortedindexby` is the giveaway about how keyframes are stored. A sorted index helper is what you reach for when you have a list of keyframes that must be looked up in time order for every frame of playback, and choosing that dependency rather than writing a binary search says the author wanted correct ordering semantics without hand-rolling them.

`shifty` sits in the same category, and it is the tweening piece of the stack. `global` is the shim for the browser global object, which is the kind of thing a library needs when it wants to reach the page environment in a way that works across bundlers and test environments.

The contrast with the development dependency list is the interesting part. That list is long and current: Vite, Vitest, c8, jsdom, jsdoc, jshint, gh-pages, concurrently, nodemon, live-server and lodash. The build and test tooling has been brought up to date, while the runtime surface has stayed at three packages.

The manifest also records two contributors, Franck Lecollinet and Brian Downing, and an overrides block pinning morgan and on-headers, which is a sign that transitive dependencies are being held in place deliberately.

Source, renderers, tests and tutorials in one tree

The repository layout matches the library's structure. There is a `src` directory for the source, a `test` directory, and a `tutorials` directory, which is the part worth noticing because it means the examples live in the repository rather than only on the documentation site. The build configuration is `vite.config.mjs`, and there is a `jsconfig.json` for editor configuration, a `.jsdoc` directory for the documentation generator, a `.jshintrc` for the linter and a `.npmrc`.

The published package is deliberately small. The `files` array in the manifest lists `src` and `dist` and nothing else, and the `main` entry points at `dist/rekapi.js` with the built bundle as the entry point, while `src` is included so that consumers can reach the source if they want it. The version is 2.5.1, and the `homepage` field in the manifest points at rekapi.com, while the repository homepage in the project metadata is the documentation site at jeremyckahn.github.io/rekapi/doc/.

There is a CONTRIBUTING.md and a LICENSE-MIT file, and the licence is MIT, which the README spells out in the plainest possible terms: you are encouraged to use and modify the code to suit your needs, as well as redistribute it.

Version 2.5.1, and a branch pushed days before this article

The recent releases are 2.5.1 from 2025-09-07, 2.5.0 from the same day, and 2.4.0 from 2025-08-11. The two releases on one day are a patch and a minor published together, which usually means a fix that could not wait for the next minor line.

The repository is not archived and the last push was on 2026-10-18, so the branch is current even though the newest published version is from the previous year. That gap is the thing to keep in mind when you evaluate the project: the npm version you install is 2.5.1, and the work on the branch is ahead of it.

The distribution channel is npm, and the repository has no GitHub releases to speak of, so the npm tag is the release marker. The version published to npm is the one whose API the documentation site describes, unless the branch has moved on, and the doc:live script exists precisely so that a contributor can read the documentation of the current source rather than the last published build.

For a library that has been stable at a 2.x line for a while, that combination, an active branch and an older published version, is a normal state for a mature project rather than a warning sign. It does mean the release process is worth watching if you depend on new features.

Editorial conclusion

Rekapi fits a project that wants a timeline of keyframes driving several visual targets at once, or that animates something the bundled renderers do not cover and can supply a renderer of its own. It is the wrong choice for a simple fade or a CSS transition, where the platform already does the job with less code. Verify first which rendering environments you actually need, because the bundled renderers cover the HTML DOM and the HTML5 2D canvas and nothing else, and check the documentation site for the API of the version you pin, since the published version is 2.5.1.

Frequently asked questions

Does Rekapi draw anything to the screen itself?

No. The README states that Rekapi is renderer-agnostic and does not perform any rendering at its core. It exposes an API for defining renderers and comes bundled with renderers for the HTML DOM and the HTML5 2D canvas.

How do I install Rekapi and load it?

Install it with npm install --save rekapi. It exposes a UMD module, so you can import { Rekapi, Actor } from 'rekapi' with ES6 modules, define it with AMD, or require it with CommonJS.

Which browsers does Rekapi support?

The README states that Rekapi officially supports Evergreen browsers. The documentation site at jeremyckahn.github.io/rekapi/doc/ carries the API reference and the tutorials.

How do I build and test Rekapi locally?

Run npm install to get the dependencies, npm run build to generate dist/rekapi.js and npm test to run the tests in the command line. npm start starts a development server, with the tests at http://localhost:9010/test/ and the documentation at http://localhost:9010/dist/doc/.

What licence is Rekapi distributed under?

MIT, with the LICENSE-MIT file at the repository root. The README encourages you to use and modify the code to suit your needs, as well as redistribute it.

Official sources

  1. jeremyckahn/rekapi on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/jeremyckahn-rekapi.svg)](https://hysenlabs.com/projects/jeremyckahn-rekapi)

Was this useful?