π§² Free, open-source Final Cut Pro-style video editor for Windows (MIT). Magnetic timeline, edit-by-transcript, silence removal, keyframes, smart-render export.
2
stars
100
commits
TypeScript
primary language
Aug 14, 2026
updated
A free, open-source, Final Cut Pro-style non-linear video editor for Windows.
Magnetic timeline Β· WebCodecs/WebGL2 playback Β· edit-by-transcript Β· auto silence removal Β· keyframe animation Β· smart-render export. Built for long-form creator workflows β multi-hour recordings play with a flat memory footprint and export at disk speed.

Portfolio project. The design is an homage to Apple's Final Cut Pro β the magnetic timeline, three-panel layout, JKL transport, and edit grammar are modeled on it as the design reference. Not affiliated with Apple; no Apple trademarks are used and "Magnetic" is an original product name.
New to Magnetic? Start with the User Guide β a five-minute first edit, the magnetic-timeline workflow, edit-by-transcript, and troubleshooting.
.mglib bundle (hardlinks instead of copies when source and library share a volume)E, insert W, connect Q, overwrite D, ripple delete, lift; select A / blade B / trim T tools; trim ripples, edit points roll, clip bodies slip; drag-rearrange with magnetic collision; full undo/redoβ/β, Β±10 with Shift), in/out marks with play-the-marked-range (/), source/sequence timecode you can click and type to seek, loop playback (Ctrl+L), fullscreen review (Shift+F), live audio meter, transport buttons in both source and sequence modes, and Space plays the browser selection when nothing else is upCtrl+C/V/D), paste-connect (Ctrl+Shift+V), paste attributes incl. keyframes (Ctrl+Alt+V); one undo step per pasteM at the playhead) that ride the media through blades, trims, and moves; ruler diamonds seek on click, the Inspector edits note/color, Ctrl+;/Ctrl+' navigate; agents drop and read them toocut_words MCP tool that matches a spoken quote and proposes the cutdocs/agent-copilot-vision.md)claude mcp add magnetic -- node scripts/magnetic-mcp.mjs), reads the open timeline (clips, roles, markers, transcript), and proposes edits that arrive as the same ghost-diff preview with a timeline banner β including the high-level cut_words (quote β cut), duck_music, and normalize_loudness tools. Nothing applies until you Accept, there is no export tool over MCP, the sidebar toggle severs all connections instantly (token-protected, 127.0.0.1 only), and requests arriving mid-drag queue until your gesture finishesShift+? lists every live bindingnpm run package, binaries bundledExplicitly out of scope: multicam, color wheels/curves/scopes, proxy workflow (preview proxies for non-decodable codecs only), compound clips, 360Β°/HDR, plugins, Motion templates, ProRes encode, object tracking, collaboration.
# 1. Install dependencies
npm install
# 2. Fetch native binaries (ffmpeg, ffprobe, whisper.cpp, base.en model)
# into resources/bin/ β pinned URLs, sha256-verified, idempotent
npm run fetch-binaries
# 3. Generate test media into fixtures/ (uses the fetched ffmpeg + Windows SAPI TTS)
npm run fixtures
npm run dev # start electron-vite dev server + app (HMR)
npm run typecheck # tsc across main, preload, renderer, shared, e2e
npm run lint # eslint
npm test # vitest unit tests
npm run build # electron-vite production build -> out/
npm run test:e2e # Playwright Electron E2E (requires `npm run build` first)
npm run package # NSIS installer + win-unpacked -> dist/ (bundles resources/bin)
The installer bundles ffmpeg/ffprobe/whisper and the base.en model (~250 MB of binaries), so the packaged app has no first-run download. e2e/packaged.spec.ts boots dist/win-unpacked/Magnetic.exe and verifies the bundled binaries resolve; it is skipped until npm run package has produced that output.
| Script | What it does |
|---|---|
dev | Run the app in development with HMR |
build | Production build to out/ |
typecheck | Typecheck node (main/preload/shared/e2e) and web (renderer) projects |
lint | ESLint over the repo |
test | Vitest unit tests (src/**/*.test.ts) |
test:e2e | Playwright _electron E2E suite against the built app |
package | electron-builder NSIS installer into dist/ |
fetch-binaries | Download + sha256-verify ffmpeg/ffprobe/whisper/model into resources/bin/ |
fixtures | Generate deterministic test media into fixtures/ |
format | Prettier write |
Generated from the live shortcut registry (scripts/dump-shortcuts.mjs); Shift+? in the app shows the same list. Shortcuts are suppressed while typing in text fields. J/K/L and Space are contextual β they drive the source viewer when it has a clip open, otherwise the timeline.
| Shortcut | Action |
|---|---|
Space | Play / pause (viewer or sequence) |
J | Viewer: play reverse (again: faster) Β· Timeline: pause |
K | Pause |
L | Play forward (again: faster) |
β / β | Step back / forward one frame |
Shift+β / Shift+β | Step back / forward 10 frames |
Home / End | Go to the start / end (viewer or timeline) |
β / β | Jump to the previous / next edit point |
I / O / X | Mark in / mark out / clear in-out points |
/ | Play the marked range (in to out) |
Ctrl+L | Loop playback on / off |
Shift+F | Fullscreen viewer |
E | Append browser selection to the spine |
W | Insert browser selection at the playhead |
Q | Connect browser selection at the playhead |
D | Overwrite at the playhead with browser selection |
Delete | Ripple delete the selected clips |
Shift+Delete | Lift the selected clips, leaving a gap |
A | Select tool |
B | Blade tool |
T | Trim tool (edges ripple, edit points roll, body slips) |
Ctrl+B | Blade at the playhead (selected clips, or the clip under it) |
Ctrl+T | Add a 1 s cross dissolve at the edit point nearest the playhead |
M | Add a marker at the playhead |
Ctrl+; / Ctrl+' | Jump to the previous / next marker |
Ctrl+Z / Ctrl+Shift+Z | Undo / redo |
N | Toggle snapping |
S | Toggle skimming |
= / - | Zoom the timeline in / out |
Shift+Z | Zoom the timeline to fit the sequence |
Ctrl+4 | Show or hide the Inspector |
Ctrl+E | Export the sequence as a movie |
Ctrl+Shift+T | Show or hide the timeline transcript |
Ctrl+Shift+D | Show or hide binary diagnostics |
Shift+? | Show the keyboard shortcut overlay |
Escape | Return focus to browser Β· close the clip grid Β· exit fullscreen |
flowchart TB
subgraph rendererBox["Renderer (src/renderer)"]
ui["React UI<br/>browser Β· viewer Β· timeline Β· inspector"]
store["zustand timeline store<br/>undo / redo"]
engine["Playback engine<br/>streaming WebCodecs demux + decode β WebGL2 compositor<br/>AudioContext-clocked sync"]
end
subgraph sharedBox["Shared (src/shared)"]
kernel["Magnetic timeline kernel<br/>pure TS Β· immutable Sequence<br/>every op returns its inverse"]
end
subgraph mainBox["Main process (src/main)"]
ipc["IPC<br/>zod-validated handlers"]
lib["LibraryStore<br/>.mglib JSON + media"]
jobs["JobQueue<br/>filmstrip Β· waveform Β· proxy<br/>transcribe Β· envelope"]
exp["Export sink<br/>rawvideo pipe β ffmpeg<br/>or smart-render stream-copy"]
end
ui --> store
store --> kernel
store --> engine
ui -->|window.api preload bridge| ipc
ipc --> lib
ipc --> jobs
ipc --> exp
src/shared/timeline/ β the magnetic-timeline kernel: pure functions over an immutable Sequence; clip positions are derived by summation so overlaps are unrepresentable; every op returns its inverse for undosrc/main/ β Electron main process: window, menu, library persistence, background jobs, export (including the smart-render planner); every IPC handler zod-validates its payloadsrc/preload/ β contextBridge bridge exposing the typed window.apisrc/renderer/ β React UI (dark FCP-style 3-panel shell), zustand state, and the playback engine (streaming WebCodecs demux + decode, WebGL2 compositing, AudioContext-clocked sync)scripts/ β binary fetcher, fixture generator, shortcut-table dumpe2e/ β Playwright Electron tests; resources/bin/ and fixtures/ are gitignored artifactsThe visual language is documented in DESIGN.md (tokens, type scale, spacing, motion β Apple dark-mode chrome where the footage is the hero) and PRODUCT.md (register, users, brand personality).
Renderer security: contextIsolation: true, nodeIntegration: false, sandbox: true, CSP set in index.html, no remote URLs; library files are served over a custom mfile:// protocol scoped to the library, except video/audio playback, which goes through a token-guarded loopback HTTP server (src/main/media-server.ts) because Chromium's media pipeline cannot seek large files through Electron custom-protocol responses. Ctrl+Shift+D toggles a diagnostics overlay that spawn-verifies the bundled binaries.
Filmstrip browser β hover-skim, ratings, background jobs | Viewer β JKL transport, frame stepping, in/out marks |
Edit-by-transcript β word-click seek, delete text to cut | Export β H.264/AAC MP4 with progress + cancel |
Shift+? overlay β every live binding | 500-clip timeline β 0.7 ms median draw |
J in the timeline pauses; true reverse playback is viewer-onlyMIT β free for everyone, for any use.
The fetch-binaries script downloads third-party tools that are not part of this repository and carry their own licenses: FFmpeg/FFprobe (GPL builds from gyan.dev), whisper.cpp (MIT), and the Whisper base.en model (MIT).
If my tools save you time, you can support my work here:
100 commits
TypeScript
94.6%
CSS
2.3%
JavaScript
2.1%
π§² Free, open-source Final Cut Pro-style video editor for Windows (MIT). Magnetic timeline, edit-by-transcript, silence removal, keyframes, smart-render export.
2
stars
100
commits
TypeScript
primary language
Aug 14, 2026
updated
A free, open-source, Final Cut Pro-style non-linear video editor for Windows.
Magnetic timeline Β· WebCodecs/WebGL2 playback Β· edit-by-transcript Β· auto silence removal Β· keyframe animation Β· smart-render export. Built for long-form creator workflows β multi-hour recordings play with a flat memory footprint and export at disk speed.

Portfolio project. The design is an homage to Apple's Final Cut Pro β the magnetic timeline, three-panel layout, JKL transport, and edit grammar are modeled on it as the design reference. Not affiliated with Apple; no Apple trademarks are used and "Magnetic" is an original product name.
New to Magnetic? Start with the User Guide β a five-minute first edit, the magnetic-timeline workflow, edit-by-transcript, and troubleshooting.
.mglib bundle (hardlinks instead of copies when source and library share a volume)E, insert W, connect Q, overwrite D, ripple delete, lift; select A / blade B / trim T tools; trim ripples, edit points roll, clip bodies slip; drag-rearrange with magnetic collision; full undo/redoβ/β, Β±10 with Shift), in/out marks with play-the-marked-range (/), source/sequence timecode you can click and type to seek, loop playback (Ctrl+L), fullscreen review (Shift+F), live audio meter, transport buttons in both source and sequence modes, and Space plays the browser selection when nothing else is upCtrl+C/V/D), paste-connect (Ctrl+Shift+V), paste attributes incl. keyframes (Ctrl+Alt+V); one undo step per pasteM at the playhead) that ride the media through blades, trims, and moves; ruler diamonds seek on click, the Inspector edits note/color, Ctrl+;/Ctrl+' navigate; agents drop and read them toocut_words MCP tool that matches a spoken quote and proposes the cutdocs/agent-copilot-vision.md)claude mcp add magnetic -- node scripts/magnetic-mcp.mjs), reads the open timeline (clips, roles, markers, transcript), and proposes edits that arrive as the same ghost-diff preview with a timeline banner β including the high-level cut_words (quote β cut), duck_music, and normalize_loudness tools. Nothing applies until you Accept, there is no export tool over MCP, the sidebar toggle severs all connections instantly (token-protected, 127.0.0.1 only), and requests arriving mid-drag queue until your gesture finishesShift+? lists every live bindingnpm run package, binaries bundledExplicitly out of scope: multicam, color wheels/curves/scopes, proxy workflow (preview proxies for non-decodable codecs only), compound clips, 360Β°/HDR, plugins, Motion templates, ProRes encode, object tracking, collaboration.
# 1. Install dependencies
npm install
# 2. Fetch native binaries (ffmpeg, ffprobe, whisper.cpp, base.en model)
# into resources/bin/ β pinned URLs, sha256-verified, idempotent
npm run fetch-binaries
# 3. Generate test media into fixtures/ (uses the fetched ffmpeg + Windows SAPI TTS)
npm run fixtures
npm run dev # start electron-vite dev server + app (HMR)
npm run typecheck # tsc across main, preload, renderer, shared, e2e
npm run lint # eslint
npm test # vitest unit tests
npm run build # electron-vite production build -> out/
npm run test:e2e # Playwright Electron E2E (requires `npm run build` first)
npm run package # NSIS installer + win-unpacked -> dist/ (bundles resources/bin)
The installer bundles ffmpeg/ffprobe/whisper and the base.en model (~250 MB of binaries), so the packaged app has no first-run download. e2e/packaged.spec.ts boots dist/win-unpacked/Magnetic.exe and verifies the bundled binaries resolve; it is skipped until npm run package has produced that output.
| Script | What it does |
|---|---|
dev | Run the app in development with HMR |
build | Production build to out/ |
typecheck | Typecheck node (main/preload/shared/e2e) and web (renderer) projects |
lint | ESLint over the repo |
test | Vitest unit tests (src/**/*.test.ts) |
test:e2e | Playwright _electron E2E suite against the built app |
package | electron-builder NSIS installer into dist/ |
fetch-binaries | Download + sha256-verify ffmpeg/ffprobe/whisper/model into resources/bin/ |
fixtures | Generate deterministic test media into fixtures/ |
format | Prettier write |
Generated from the live shortcut registry (scripts/dump-shortcuts.mjs); Shift+? in the app shows the same list. Shortcuts are suppressed while typing in text fields. J/K/L and Space are contextual β they drive the source viewer when it has a clip open, otherwise the timeline.
| Shortcut | Action |
|---|---|
Space | Play / pause (viewer or sequence) |
J | Viewer: play reverse (again: faster) Β· Timeline: pause |
K | Pause |
L | Play forward (again: faster) |
β / β | Step back / forward one frame |
Shift+β / Shift+β | Step back / forward 10 frames |
Home / End | Go to the start / end (viewer or timeline) |
β / β | Jump to the previous / next edit point |
I / O / X | Mark in / mark out / clear in-out points |
/ | Play the marked range (in to out) |
Ctrl+L | Loop playback on / off |
Shift+F | Fullscreen viewer |
E | Append browser selection to the spine |
W | Insert browser selection at the playhead |
Q | Connect browser selection at the playhead |
D | Overwrite at the playhead with browser selection |
Delete | Ripple delete the selected clips |
Shift+Delete | Lift the selected clips, leaving a gap |
A | Select tool |
B | Blade tool |
T | Trim tool (edges ripple, edit points roll, body slips) |
Ctrl+B | Blade at the playhead (selected clips, or the clip under it) |
Ctrl+T | Add a 1 s cross dissolve at the edit point nearest the playhead |
M | Add a marker at the playhead |
Ctrl+; / Ctrl+' | Jump to the previous / next marker |
Ctrl+Z / Ctrl+Shift+Z | Undo / redo |
N | Toggle snapping |
S | Toggle skimming |
= / - | Zoom the timeline in / out |
Shift+Z | Zoom the timeline to fit the sequence |
Ctrl+4 | Show or hide the Inspector |
Ctrl+E | Export the sequence as a movie |
Ctrl+Shift+T | Show or hide the timeline transcript |
Ctrl+Shift+D | Show or hide binary diagnostics |
Shift+? | Show the keyboard shortcut overlay |
Escape | Return focus to browser Β· close the clip grid Β· exit fullscreen |
flowchart TB
subgraph rendererBox["Renderer (src/renderer)"]
ui["React UI<br/>browser Β· viewer Β· timeline Β· inspector"]
store["zustand timeline store<br/>undo / redo"]
engine["Playback engine<br/>streaming WebCodecs demux + decode β WebGL2 compositor<br/>AudioContext-clocked sync"]
end
subgraph sharedBox["Shared (src/shared)"]
kernel["Magnetic timeline kernel<br/>pure TS Β· immutable Sequence<br/>every op returns its inverse"]
end
subgraph mainBox["Main process (src/main)"]
ipc["IPC<br/>zod-validated handlers"]
lib["LibraryStore<br/>.mglib JSON + media"]
jobs["JobQueue<br/>filmstrip Β· waveform Β· proxy<br/>transcribe Β· envelope"]
exp["Export sink<br/>rawvideo pipe β ffmpeg<br/>or smart-render stream-copy"]
end
ui --> store
store --> kernel
store --> engine
ui -->|window.api preload bridge| ipc
ipc --> lib
ipc --> jobs
ipc --> exp
src/shared/timeline/ β the magnetic-timeline kernel: pure functions over an immutable Sequence; clip positions are derived by summation so overlaps are unrepresentable; every op returns its inverse for undosrc/main/ β Electron main process: window, menu, library persistence, background jobs, export (including the smart-render planner); every IPC handler zod-validates its payloadsrc/preload/ β contextBridge bridge exposing the typed window.apisrc/renderer/ β React UI (dark FCP-style 3-panel shell), zustand state, and the playback engine (streaming WebCodecs demux + decode, WebGL2 compositing, AudioContext-clocked sync)scripts/ β binary fetcher, fixture generator, shortcut-table dumpe2e/ β Playwright Electron tests; resources/bin/ and fixtures/ are gitignored artifactsThe visual language is documented in DESIGN.md (tokens, type scale, spacing, motion β Apple dark-mode chrome where the footage is the hero) and PRODUCT.md (register, users, brand personality).
Renderer security: contextIsolation: true, nodeIntegration: false, sandbox: true, CSP set in index.html, no remote URLs; library files are served over a custom mfile:// protocol scoped to the library, except video/audio playback, which goes through a token-guarded loopback HTTP server (src/main/media-server.ts) because Chromium's media pipeline cannot seek large files through Electron custom-protocol responses. Ctrl+Shift+D toggles a diagnostics overlay that spawn-verifies the bundled binaries.
Filmstrip browser β hover-skim, ratings, background jobs | Viewer β JKL transport, frame stepping, in/out marks |
Edit-by-transcript β word-click seek, delete text to cut | Export β H.264/AAC MP4 with progress + cancel |
Shift+? overlay β every live binding | 500-clip timeline β 0.7 ms median draw |
J in the timeline pauses; true reverse playback is viewer-onlyMIT β free for everyone, for any use.
The fetch-binaries script downloads third-party tools that are not part of this repository and carry their own licenses: FFmpeg/FFprobe (GPL builds from gyan.dev), whisper.cpp (MIT), and the Whisper base.en model (MIT).
If my tools save you time, you can support my work here:
100 commits
TypeScript
94.6%
CSS
2.3%
JavaScript
2.1%