Generate videos
from familiar web code,
without browsers.

Define your video in typed JSON. Use JSX and CSS to render custom visuals and animations in Node.js. Tie it all together over HTTP.

Pure FFmpeg under the hood. No Puppeteer. No Chrome. No headaches. Faster, cheaper, and easier to scale.

And you can run it all yourself — no vendor lock-in.

$ npm create @effing my-effing-app

Three basic building blocks.

A JSON format for video compositions, a TAR format for animations that slot into compositions, and a service that turns compositions into MP4s. Everything in between is just URLs — asset generation and rendering are fully decoupled.

Effie
Declarative composition format
JSON that describes how to combine images, audio, animations, transitions, and effects into a final video. Typed, portable, and framework-agnostic.
Annie
Streamable animation format
A TAR archive of PNG or JPEG frames. Generate them server-side from JSX, or however you like. Playable in the browser, composable into videos.
FFS
FFmpeg rendering service
Takes an Effie composition, builds an FFmpeg filter chain, fetches all assets by URL, and produces an MP4. Use it as a library or a standalone HTTP server.
See how they connect in the tutorial →

From JSX to pixels, directly.

Effing Canvas is a great way to generate Annie frames and static images. Write the same JSX and CSS properties you use on the web. Yoga handles layout, Skia handles rendering. The result is an image, rendered directly — no DOM involved.

title.tsx
const canvas = createCanvas(1080, 1920)
const ctx = canvas.getContext("2d")

await renderReactElement(ctx,
  <div style={{
    display: "flex",
    alignItems: "center",
    justifyContent: "center",
    backgroundColor: "#151716",
  }}>
    <div style={{
      fontSize: 80,
      fontWeight: 700,
      color: "#4CAE4C",
    }}>
      My Video
    </div>
  </div>,
  { fonts }
)

const png = await canvas.encode("png")

Flexbox layout

Powered by Yoga. The same model you use in CSS and React Native.

CSS properties

Fonts, gradients, borders, shadows, transforms, opacity — styled the way you expect.

Emoji support

Automatic emoji rendering from CDN sources — Twemoji, Noto, Fluent, and more.

Lottie as well

Not just JSX. You can also render After Effects animations frame by frame, via Skottie, on the same canvas.

A modular TypeScript toolkit.

Effie, Annie, FFS, and Canvas are all separate packages. So are the tweening utilities and everything else. Use them together as a pipeline, or pull in just the pieces you need.

See all packages →

Everything is just a URL.

Annies and effies can be served as HTTP endpoints. Props go in the URL, assets come back. So you can simply use an HTTP framework to tie it all together. That's exactly what @effing/create sets you up with.

Framework-agnostic

Serve annies and effies from any HTTP framework. Express, Hono, React Router — if it handles requests, it works.

CDN-ready

URLs are signed and deterministic. Same URL, same output. Put a CDN in front and caching just works. Streaming prevents timeouts.

Fully decoupled

Generation and rendering don't need to know about each other. FFS fetches compositions and assets by URL — they can live anywhere.

Start making videos.

Scaffold a project, preview in the browser, render to MP4.

$ npm create @effing my-effing-app