An open-source motion editor for the desktop. Compositions, layers, keyframes, a graph editor, 3D space with cameras and lights, effects, masks and mattes, per-glyph text animators, mesh rigging, particles, and a deterministic export pipeline — built on a GPU render engine that runs on WebGPU or WebGL2.
It is modelled on After Effects' Classic 3D workflow: if you know AE, the tools, the panel layout and most of the keyboard shortcuts are already where you expect them.
Electron + React + TypeScript. Everything renders through one engine, the same engine that exports, so what you see in the viewport is what lands in the file.
License: GNU AGPL v3.0 · Status: pre-1.0, in active development
We're live on Product Hunt — an upvote helps more people find the project:
- Two editions
- Quick start
- Requirements
- What's in the box
- Export
- Projects on disk
- The AI assistant
- Repository layout
- Plugins
- Testing
- Packaging a release
- Contributing
- Documentation
- License
The same source tree builds two editions, chosen at build time with
VITE_EDITION. This exists because the editor is open source while the hosted
backend service is not.
local (VITE_EDITION=local) |
server (default) | |
|---|---|---|
| Accounts / sign-in | none — opens straight into the editor | required |
| Projects | on disk, .motion bundle |
cloud, with autosave |
| Assets | on disk, content-addressed | cloud library |
| Export | local ffmpeg | local ffmpeg |
| AI assistant | not included | via the hosted gateway |
| Billing / sync / plugin registry | absent | available |
The local edition is the one to build from this repository. It makes no
network requests at all: the API layer refuses to send, so an offline build
cannot quietly phone home. The server edition targets a backend service that
is not part of this repository, so its cloud features will not work without one.
Read the edition as a capability, never as a flag — see
src/core/config/edition.ts.
git clone https://github.com/isroil01/motion-editor.gitcd motion-editor && npm installRun the desktop app:
npm run electron:dev:localThat compiles the Electron main process, starts Vite, and opens the app. Edits to renderer code hot-reload.
To run just the renderer in a browser tab (faster, but no filesystem, native menus or ffmpeg export):
npm run dev:localBoth :local scripts set VITE_EDITION=local. Dropping the suffix
(npm run electron:dev) builds the server edition, which will sit on a sign-in
screen unless you point it at a backend.
-
Node.js 20 or newer and npm.
-
A GPU that supports WebGPU or WebGL2. The engine picks WebGPU when available and falls back to WebGL2; there is no software rasteriser.
-
ffmpeg, for
.mp4/.movexport only. Everything else — including the editor itself and webm/GIF/PNG/Lottie export — works without it. The app looks for ffmpeg in this order:$FFMPEG_PATH- a binary bundled next to the packaged app
ffmpegon yourPATH
If it finds none, mp4 export fails with a message saying exactly that, and nothing else is affected.
Linux, macOS and Windows are all supported by the toolchain. CI currently exercises the render tests only.
Counts below were taken from the source, not from memory — if you change a registry, this section is expected to drift, so re-check before quoting it.
Compositing and layout
- Nested compositions and comp instances, with collapse-transformation
- 2D and 3D layers in one space, with cameras and lights (parenting included)
- Masks, track mattes, blend modes, layer styles
- Shape layers, paths, trim paths, repeaters, path operations
- 174 effects (
src/core/effects/effects.ts)
Animation
- Keyframes with full easing control and a graph editor
- 39 presets — 15 animation, 18 text, 6 behaviour
- Per-glyph text animators with a real selector stack
- Expressions
- Bone and puppet mesh rigging (FK, linear-blend skinning, FABRIK IK, ARAP)
- Particles, motion blur, motion paths
Import
- Video, audio and images
- SVG — static files import as one intact layer; animated SVG (CSS or SMIL) converts to keyframes
- Lottie / Bodymovin
Engine
- One GPU render graph, WebGPU or WebGL2, used by the viewport and the exporter
- 3D transforms, extrusion, bevels, per-fragment shading
- Golden-image render tests to keep output stable across refactors
mp4, mov, webm, GIF, PNG/JPG sequences, and Lottie/JSON.
Frames are rasterised by the same engine that draws the viewport, streamed to disk one at a time (so peak memory is one frame, not the whole render), and muxed by a local ffmpeg process. A long export leaves the app usable.
A project is a .motion directory bundle, not a single opaque file:
MyProject.motion/
├── manifest.json written last, so a crash can't corrupt the bundle
├── scene.json ├─ separate chunks, content-hashed, so a save
├── animation.json │ writes only what actually changed
├── timeline.json │
├── meta.json ┘
├── assets/ imported media, addressed by SHA-256
└── versions/ local version history, structurally shared
Saving is incremental and version history is local — snapshots share unchanged objects rather than storing full copies, so an animation-only change costs one new object.
The editor contains a complete AI layer: 62 tools it can call, an agent loop, a deterministic "caster" pipeline that assembles motion from a hand-authored technique library, and a self-critique pass.
The local edition does not include it. Not "disabled pending work" — the surface is absent: no panel in the sidebar, no commands, no settings tab, and no AI IPC registered in the desktop shell at all.
That is a distribution decision, not a technical limit, and the previous wording
here implied the opposite — so it is worth being exact. The bring-your-own-key
path exists and works: the shell holds provider keys in the OS keystore and makes
the model call from the main process, which is how a desktop build reaches a
provider without the key ever entering renderer scope. None of that code was
removed. aiEnabled() in src/core/config/edition.ts is the entire gate.
What it means for a build from this repository: it makes no network requests at all. The API layer refuses to send, and the one piece of code here that contacts a third-party host — the provider proxy — is never registered. That guarantee now holds in the main process rather than resting on the UI declining to offer a button.
Everything else in the editor works fully offline.
src/
├── core/ document model, engine glue, commands, export, AI, plugins
│ └── config/ edition + feature flags
├── layout/ panels — timeline, inspector, workspace, effects
├── components/ reusable UI primitives
├── stores/ Zustand state
└── routes/ app shell and routing
packages/
├── scene/ scene graph, transforms, hit-testing
├── animation/ keyframes, easing, evaluation
├── timeline/ timeline model
├── renderer/ GPU render graph (WebGPU + WebGL2)
├── audio/ audio graph
├── workspace/ viewport interaction, gizmos
├── ai-tools/ the tool registry the assistant calls
├── caster/ deterministic generative pipeline
├── technique-library/ hand-authored motion techniques
├── design-system/ look packs and design tokens
├── product-motion/ UI-motion technique packs
└── render-tests/ golden-image harness
electron/ main process, IPC, native integration
Plugins are packages — a plugin.json manifest plus an ES module — that run in a
dedicated Worker sandbox. Permissions are shown and accepted before any plugin
code is loaded anywhere, and packages are signed.
See docs/PLUGINS.md for the architecture and the authoring
guide. Installing from a local file works in every edition; the hosted registry
does not exist in the local edition.
npm testRoughly 440 suites and 4,800 tests, and they are fast (under a minute). Also:
npm run typechecknpm run lintGolden-image render tests compare real GPU output against committed reference frames:
npm run render-testsnpm run render-tests:updateOnly update goldens when you have looked at the diff and can say why the new pixels are correct.
npm run dist:localProduces an installer in release/ via electron-builder. npm run pack:local
builds an unpacked directory instead, which is much faster for testing.
Contributions are welcome — see CONTRIBUTING.md for how to set up, what the review bar is, and which areas need help. By participating you agree to the Code of Conduct.
Security issues should not be filed as public issues — see SECURITY.md.
Start here: docs/EDITOR_REFERENCE.md — what the
editor does, what it does not, and an honest gap analysis against After Effects.
Its feature counts are derived from the registries by scripts/featureCounts.cjs
and pinned by src/__tests__/docFeatureCounts.test.ts, so they cannot silently
go stale.
Deep dives on individual subsystems:
docs/3d-layer-model.md— the 3D model, and where it departs from After Effectsdocs/BONE_AND_PUPPET_RIGGING.md— mesh deformation, the math and the current gapsdocs/ANIMATED_SVG_PIPELINE.md— SVG import, end to enddocs/PLUGINS.md— plugin architecture and authoringdocs/MOTION_FORMAT_FREEZE.md— what the.motionbundle is, the six migrations behind it, and what a 1.0 compatibility promise would actually require
Prose drifts faster than code. Where a document and the source disagree, the source is right — and a PR fixing the document is very welcome.
Copyright © Premation contributors.
Licensed under the GNU Affero General Public License v3.0 only. The full text is in LICENSE.
In short: you may use, study, modify and redistribute this software, but derived works must also be licensed under the AGPL and must carry the same source-code offer. Section 13 matters in particular — if you run a modified version as a network service, you must offer its users the corresponding source.
The AGPL covers this repository. It does not cover the separate hosted backend service, which is not distributed here.