kinetograph.
Plugins

Library adapters

Small published packages that make GSAP, Motion, anime.js and p5.brush show the same frame alone, in order or in parallel.

A frame is a function of the frame number. These four packages make a library follow that rule. Each has its library, react and @kinetographdev/core as peer dependencies. The list of what runs is in the Libraries section of the compatibility page.

GSAP

npm install @kinetographdev/gsap gsap

useGsapTimeline(build) builds a paused timeline and seeks it to frame / fps every frame. The returned ref scopes string selectors. <GsapTimeline build={...}> is the component form.

import { useGsapTimeline } from '@kinetographdev/gsap';

const scope = useGsapTimeline((tl) => {
  tl.fromTo('.box', { y: 120, opacity: 0 }, { y: 0, opacity: 1, stagger: 0.08, ease: 'back.out(1.7)' }, 0.1);
});
return <div ref={scope}>{/* elements with className="box" */}</div>;

Put every tween on tl. A gsap.to(...) that is not on the timeline plays on GSAP's root clock and gets a warning (see GSAP).

anime.js

npm install @kinetographdev/anime animejs

useAnimeTimeline(build) makes a paused timeline and seeks it to the frame's time. <AnimeTimeline> is the component form.

import { useAnimeTimeline } from '@kinetographdev/anime';

const scope = useAnimeTimeline((tl) => {
  tl.add('.a', { translateX: [0, 700], rotate: 360, ease: 'outExpo', duration: 900 }, 0);
});
return <div ref={scope}>{/* elements with className="a" */}</div>;

An animate(...) that is not on the timeline is warned about. A width tween that starts from 0 on an element with inline width: 0 shows nothing yet. Start from a small number, or tween scaleX.

Motion

npm install @kinetographdev/motion motion

Motion's own loop already gives the same frame in a still, in order and in parallel. The package keeps the same project right under Remotion and adds a way that needs no frame loop.

import { MotionFrame, useAnimateAt, useMotionTime, useSpringAt } from '@kinetographdev/motion';

// motion components: Motion's loop is run to the frame's time, from time 0
<MotionFrame>
  <motion.div initial={{ x: 0 }} animate={{ x: 400 }} transition={{ type: 'spring', stiffness: 60, damping: 8 }} />
</MotionFrame>

// animate(): paused, controls.time = frame / fps
useAnimateAt(() => animate(ref.current!, { x: [0, 400], rotate: 360 }, { duration: 1.5 }));

// no frame loop: a MotionValue and a spring that are functions of the frame
const x = useTransform(useMotionTime(), [0, 1500], [0, 400]);
const y = useSpringAt({ to: 120, stiffness: 60, damping: 8, delay: 10 });

MotionFrame needs Motion 14.6 or later. On an older Motion it does nothing and says so. A useSpring that follows a changing value depends on the frames visited before, so use useSpringAt or useMotionTime for those.

p5.brush

npm install @kinetographdev/p5-brush p5.brush

p5.brush keeps state between calls. <BrushCanvas> resets it on every frame: it clears the canvas, seeds the random and noise generators, draws and flushes.

import { BrushCanvas } from '@kinetographdev/p5-brush';

<BrushCanvas seed={7} background="#f4efe6" origin="top-left" draw={(brush, frame) => {
  brush.set('HB', '#2f2a26', 1.4);
  brush.line(120, 140, 120 + frame * 10, 260);
}} />

p5.brush's origin is the middle of the canvas. origin="top-left" moves it to the corner. The canvas is the composition's size unless you pass width and height.

Libraries without an adapter

These need only the same habit: compute from the frame and keep the library's own timers out.

  • d3: scales, shapes and layouts, drawn by React as SVG. Skip d3-transition and d3-timer.
  • rough.js: pass a seed to every shape.
  • Chart.js: set animation: false, then update the chart from the frame with chart.update('none').
  • Recharts: set isAnimationActive={false} on every series and slice the data by frame.
  • Paper.js: make one PaperScope, then clear and redraw every frame.
  • Matter.js and Rapier: step the world from the start to the frame with a seeded generator. A long simulation gets slow, so keep the step cheap or bake the positions first.
  • Remotion packages: @remotion/motion-blur, @remotion/layout-utils and @remotion/captions work as in Remotion.

On this page