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.
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.
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.
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")
Powered by Yoga. The same model you use in CSS and React Native.
Fonts, gradients, borders, shadows, transforms, opacity — styled the way you expect.
Automatic emoji rendering from CDN sources — Twemoji, Noto, Fluent, and more.
Not just JSX. You can also render After Effects animations frame by frame, via Skottie, on the same canvas.
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.
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.
Serve annies and effies from any HTTP framework. Express, Hono, React Router — if it handles requests, it works.
URLs are signed and deterministic. Same URL, same output. Put a CDN in front and caching just works. Streaming prevents timeouts.
Generation and rendering don't need to know about each other. FFS fetches compositions and assets by URL — they can live anywhere.
Scaffold a project, preview in the browser, render to MP4.
npm create @effing my-effing-app