I built a motion design studio in the browser. Here's what it took.
AtomCut started as a tool that was supposed to animate text. Today it's an infinite canvas above a multi-track timeline, in the browser, where you can keyframe anything, paint with a wet watercolour brush, track motion,
AtomCut started as a tool that was supposed to animate text. Today it's an infinite canvas above a multi-track timeline, in the browser, where you can keyframe anything, paint with a wet watercolour brush, track motion, add captions that follow a voice, and export to MP4, GIF, SVG or Lottie. It's free, there's no account, and it works offline.
This is the honest version of how it got there, because the tidy version ("I had a vision and executed") isn't useful to anyone building something ambitious on their own time.
It started as a typing animation
The folder is still called typomation. The first thing it did was type words onto a frame, one letter at a time, with a sound on each keystroke, so a short clip could have a title that arrived the way a typewriter would put it there.
The problem with a tool that only does one thing well is that the second thing you need is always outside it. I needed a background clip under the text. Then a sound on each letter. Then the text had to move along a path. By the time I had those, I had a timeline that didn't care what kind of clip sat on it, and the question stopped being "what should a text tool do" and became "what is the smallest set of ideas that makes everything else a special case".
The one rule everything else hangs on
Anything that describes what an animation is lives in a pure package with no DOM and no React. Anything that describes how it's shown or edited lives in the app. That's the whole architecture, and every good week I had came from it.
Concretely: a project is one JSON document, validated with zod, versioned. The document is at schema version 71 today, and every one of those migrations still runs, so a project from the first month opens. Rendering a frame is a pure function: (document, time) → what you see. Playback, scrubbing, the MP4 exporter, the PNG sequence exporter and the Lottie exporter all call the same function. There is no "export renderer" that drifts from the "preview renderer", because there's only one.
Undo is patches, not snapshots. Every mutation runs through one store that records a forward patch and an inverse patch. Undo cost is proportional to the size of the change, not the size of the project, and a continuous gesture (dragging a keyframe for two seconds) coalesces into one history entry.
None of this is novel. It's the same shape Figma and Photoshop ended up at. What I'm saying is that if you start there, a lot of features become a union variant and a registry row instead of a rewrite. A group on the timeline is a clip that happens to contain rows. A caption is a text clip with a cue map. A flipbook is a nested composition whose cells are drawings. When the primitives are right, the feature list grows without the codebase growing the same way.

The studio: canvas above, timeline below. Two layers selected, the caption
What was actually hard
Not the effects. Thirty-six layer effects sounds like the hard part; it's the easy part, because an effect is a shader and a settings card, and the keyframe engine already animates any number.
The hard parts were the ones where two true things fight:
A cropped video has two things you can move. The window and the picture inside it. If you store that as one transform plus four insets, every keyframed reframe visibly swims between keys, because three animated quantities cancel to a constant that the interpolation doesn't know about. The fix was two transforms, one for the window and one for the content, and a rule that the content transform never reads the crop. It took a week to see that the bug was in the data model and not in the interpolation.
A mirrored layer is a negative scale, and nothing else. I had a flipX flag for a while. A flag plus a sign is two fields for one fact, and they disagreed the moment a keyframe interpolated across a flip. Deleting the flag deleted a family of bugs.
A frame rate is a grid, never a time. There is no project-wide fps. Each composition carries its own, and a rate only ever quantises: it's what the ruler ticks on, what the arrow keys step by, what export iterates on. A 12 fps flipbook inside a 60 fps comp holds each cell for 83.33 ms and nothing resamples anything, so nothing can drift. The earlier version had a global rate plus overrides, and half the app read one while half read the other.
The crop one cost the most. I fixed the interpolation three times before I admitted the data was wrong.
The changelog is the spec
Every change has to earn one line in a public changelog, written before the code: what can a user do now that they couldn't before. If I can't write that line, the change doesn't ship. It sounds like process; it's actually the fastest way I've found to kill work that only feels productive. Half of what I started never got its line.
What it's bad at
Cutting a two-hour 4K timeline. It renders in the browser; a native NLE will beat it on heavy footage. It's young, so you will find rough edges; when someone reports one, it's usually fixed in the next release, and you can watch that happen in the changelog.
What's next
It's free and it stays free. Exports are capped at 720p; $29 once, not a subscription, removes the cap. After that, the plan is live collaboration, an assistant inside the editor that can operate the timeline, and the plugin SDK opening up.
If you make anything with it, I'd like to see it. It opens at app.atomcut.net with no signup.
Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.