@blinn-motion/react wraps the engine in a component and a hook. Pick the paint backend with one prop; drive playback through a ref.

Install

npm i @blinn-motion/react

The component

import { BlinnMotion } from "@blinn-motion/react";
import doc from "./card.motion.json";

export default function Hero() {
  return (
    <BlinnMotion
      doc={doc}
      renderer="canvas"   // or "dom"
      loop
      autoplay
    />
  );
}

Props

doc
MotionDoc
required
The animation document to play.
renderer
"dom" | "canvas"
default:"\"dom\""
Which adapter paints the resolved tree.
loop
boolean
default:"false"
Restart when the timeline ends.
autoplay
boolean
default:"false"
Start playing on mount.
onFrame
(t: number, fraction: number) => void
Per-frame callback for scrubbers and timecode readouts.

Driving playback with a ref

import { useRef } from "react";
import { Blinn Motion, type BlinnMotionHandle } from "@blinn-motion/react";

function Controlled({ doc }) {
  const ref = useRef<BlinnMotionHandle>(null);
  return (
    <>
      <BlinnMotion ref={ref} doc={doc} renderer="dom" />
      <button onClick={() => ref.current?.toggle()}>Play / pause</button>
      <input
        type="range" min={0} max={1} step={0.001}
        onChange={(e) => ref.current?.seekFraction(Number(e.target.value))}
      />
    </>
  );
}
The ref exposes the same surface as every adapter: play, pause, toggle, seek, seekFraction and loop.