blog

Build a canvas video editor (or embed one)

A canvas video editor is three machines that must agree: a document model, a compositor, an exporter. An honest map of building them, from a team that did, and the three-line embed for everyone else.

Ian Scott
Ian Scott
Founder, Clipkit · August 18, 2026

"Canvas video editor" usually means one of two projects. Either you're building one (a timeline editor rendering to a canvas inside your product) or you're looking for one that already works in the browser. This post takes both seriously: first an honest map of what building one actually involves, because we did it and most of the cost is invisible from the outside, then the shortcut, because the editor we built is Apache-2.0 and embeddable.

What "a canvas video editor" actually is#

Strip the UI away and a canvas video editor is three machines that must agree with each other:

  1. A document model. Tracks, clips, timing, transforms, effects, audio. Every editing operation is a mutation of this model, and undo, collaboration, and templating all depend on it being plain data rather than scattered component state.
  2. A compositor. Something that can take the document plus a time t and paint the correct frame. On the web that's a <canvas>, and in practice a WebGL2 or WebGPU context, because 2D canvas runs out of compositing power (blend modes, blurs, masks, particles) almost immediately.
  3. An exporter. Something that turns the same document into an MP4 users can keep. In the browser that's WebCodecs; the moment you leave the browser it's a headless renderer or a server farm.

The editor part (the timeline, the inspector, the drag handles) sits on top and is honestly the most tractable of the four. It's also the only part most build estimates include.

The parts that eat the schedule#

We ship a production editor on this stack, so this list comes from commits rather than intuition.

Frame-accurate seeking. A <video> element seeks when it feels like it and reports time approximately. A timeline scrubber can't work that way: when the playhead sits at frame 241, every layer (video clips included) must show exactly frame 241's state. That means decoding video yourself (WebCodecs again, on the way in), managing decode buffers, and never trusting currentTime.

Determinism. Preview and export must produce the same pixels, or users watch one video and download another. This constraint is architectural, not a bug fix: every animation must be a pure function of time (seek-safe, no accumulating state), every effect deterministic, every random particle seeded. Retrofitting determinism into a compositor that grew organically is the single most expensive mistake available in this project.

Export is encoder-bound and hardware-tiered. In-browser MP4 export through WebCodecs runs at roughly 222 fps for 1080p on an Apple M4 and 4 to 5 fps on an older Intel i9 in our measurements. Same code, 50x spread. You'll want progress UI, cancellation, and eventually a server-side path for the users on the slow end of that spread.

Text is a rabbit hole with no bottom. Fonts load asynchronously (render before they arrive and you export the fallback font), line breaking and emoji need real text shaping, and per-word animation means measuring and laying out fragments yourself. Text is the most-used element type in every editor we've seen data for, so none of this is optional.

Audio. Multiple tracks mixed with per-clip gain, in sync during scrubbing (which means resampling short windows on seek), and encoded into the same container on export. Video-only demos hide this; users don't.

None of this is impossible, and if video editing is your product, building the compositor is defensible. Our runtime alone is tens of thousands of lines of GPU and codec code, so the realistic estimate for the full stack is engineer-years, not sprints. The question is whether that's the moat you want to fund.

The embed path#

The other answer to "canvas video editor" is three lines in a React app:

import { Editor } from "tok-str">'@clipkit/editor';

<Editor initialSource={project} />;

That renders the full editor (timeline, keyframes, expressions, every panel); configurations let you slim the surface down when your product wants less.

@clipkit/editor is the timeline UI from the map above, Apache-2.0, with the three machines already agreeing underneath: the document model is the Clipkit Protocol (an open JSON schema, so your backend and your agents can write it too), the compositor is a deterministic WebGPU/WebGL2 runtime, and export runs through WebCodecs in the tab. Storage is an injected adapter, so assets land in your S3 or Supabase, and onSourceChange hands you the document JSON to persist wherever rows live in your stack.

You can gut-check it in one minute: the no-login editor on this site is the same component with a demo adapter. The architecture page shows how the editor relates to the runtime and the rest of the stack, and if your actual question is "React app, video feature, fastest path", the sibling post on adding a video editor to a React app walks the integration end to end.

Build or embed, honestly#

Build when the editor is the product and its behavior is your differentiation: you'll need the control eventually, and owning the compositor is how you get it. Embed when video editing is a feature inside a bigger product: the engineer-years above buy you nothing your users asked for, and the protocol underneath keeps an escape hatch open (it's Apache-2.0 and independently implementable, so your documents are never hostage to our implementation).

And if you're partway down the build already, the protocol is worth a look even without the editor: adopting a proven document model is free, and it's the machine the other two agree through.

faq

Questions, answered straight.

How hard is it to build a video editor in the browser?
The timeline UI is the tractable part; the compositor and exporter underneath are where the time goes. Frame-accurate seeking means decoding video yourself instead of trusting a <video> element, preview/export parity demands determinism throughout, and text, audio, and fonts each hide months of edge cases. Our runtime alone is tens of thousands of lines of GPU and codec code, so realistic estimates run in engineer-years, not sprints.
Can I build a video editor with plain 2D canvas?
You can prototype one, and it runs out of headroom fast. Compositing real videos means blend modes, blurs, masks, group transforms, and particles at 30 or 60 fps, which is GPU work: WebGL2 or WebGPU in practice. That's also why 2D-canvas editors tend to cap out at slideshow-grade output while GPU-compositor editors don't.
How do browser-based video editors export MP4?
Through WebCodecs: the compositor paints each frame, the encoder turns frames plus mixed audio into an MP4, all client-side with no render server. Speed is the user's hardware: we measure roughly 222 fps at 1080p on an Apple M4 and 4 to 5 fps on an older Intel i9, a 50x spread the same code has to survive. Server-side rendering enters when users need guaranteed speed or formats browsers can't encode.
Why can't the preview just use a <video> element?
Because a timeline scrubber needs the exact frame at time t, and <video> seeks approximately and asynchronously. With the playhead parked at frame 241, every layer must show frame 241's state, which means decoding clips yourself and managing buffers. It's the first place a naive build diverges from a usable one.
Is there an open-source canvas video editor I can embed instead?
Yes: @clipkit/editor is an Apache-2.0 React timeline editor over a deterministic WebGPU/WebGL2 compositor, with in-browser WebCodecs export and storage injected through an adapter you implement. The document it edits is an open JSON protocol, so your backend and your agents can author videos too. The no-login editor on clipkit.dev is the stock component, so you can evaluate it before installing anything.
See it render, right now

The editor runs in your browser — no login, no watermark, free export.

Open the editorConnect an agent