"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:
- 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.
- A compositor. Something that can take the document plus a time
tand 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. - 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.