| initial load |
GPU-first editing with 30 effects, 37 blend modes, 79 AI tools, native WebGPU 3D, and only 15 runtime dependencies.
Built from scratch in 2,700+ lines of WGSL and 165k lines of TypeScript.
Import .lottie, Lottie JSON, OBJ, glTF, GLB, PLY, SPLAT, KSPLAT, SPZ, SOG, LCC assets and play PLY / GLB sequences directly on the timeline.
masterselects_github.mp4
Decoding depends on what the browser supports — the container is just the wrapper, the codec inside is what matters.
| Import (Decode) | |
|---|---|
| Video files | MP4, WebM, MOV, AVI, MKV, WMV, M4V, FLV |
| Video codecs | H.264 (AVC), H.265 (HEVC)¹, VP8, VP9, AV1 |
| Audio files | WAV, MP3, OGG, FLAC, AAC, M4A, WMA, AIFF, OPUS |
| Image | PNG, JPG/JPEG, WebP, GIF, BMP, SVG |
| Vector animation | .lottie packages and Lottie JSON files (content-sniffed) |
| 3D Models | OBJ, glTF, GLB - rendered through the native WebGPU shared-scene path |
| 3D sequences | PLY and GLB frame sequences played as timeline media |
| Gaussian Splats | PLY, compressed PLY, SPLAT, KSPLAT, SPZ, SOG, LCC, SOG-style ZIP payloads |
| Download | YouTube, TikTok, Instagram, Twitter/X, Vimeo + all yt-dlp sites via Native Helper |
| Export (Encode) | |
| Video containers | MP4, WebM via WebCodecs / HTMLVideo; MOV, MKV, AVI, MXF via FFmpeg WASM |
| FFmpeg codecs | ProRes, DNxHR, FFV1, UTVideo, MJPEG |
| Video codecs | H.264, H.265¹, VP9, AV1 — GPU-accelerated via WebCodecs |
| Image export | PNG, JPG/JPEG, WebP, BMP (current playhead frame) |
| Audio-only export | AAC or OGG/Opus depending on browser codec support |
| Interchange | FCPXML (Final Cut Pro / DaVinci Resolve) |
¹ H.265 decode/encode depends on OS & hardware — full support on Windows, partial on macOS/Linux.
MOV files work because they share the same ISO BMFF container as MP4 — any MOV with H.264/H.265 inside plays fine. MKV works if it contains browser-decodable codecs (H.264, VP9, etc.). Files with unsupported codecs (e.g. ProRes in MOV) fall back to the Native Helper decode path when available.
Most browser-based video editors share a pattern: Canvas 2D compositing, heavyweight dependency trees, and CPU-bound rendering that falls apart at scale. This project takes a fundamentally different approach.
GPU-first architecture. Preview, scrubbing, and export all run through the same WebGPU ping-pong compositor. Video textures are imported as texture_external (zero-copy, no CPU roundtrip). 37 blend modes, 3D rotation, and inline color effects all execute in a single WGSL composite shader per layer. The 3D layer system now renders through the native WebGPU shared-scene path for 3D planes, primitive meshes, 3D text, OBJ/glTF/GLB models, camera clips, and gaussian splats - no GSAP, no Canvas 2D fallback in the hot path.
Current startup footprint. The production app shell is currently about 1.5 MB gzip on first load. The largest contributors are the native 3D / gaussian-splat render path, browser-side media parsing/runtime code, and AI/media helper modules. Reducing the initial bundle again is an active optimization target.
Zero-copy export pipeline. Frames are captured as new VideoFrame(offscreenCanvas) directly from the GPU canvas. No readPixels(), no getImageData(), no staging buffers in the default path. The GPU renders, WebCodecs encodes. That's it.
3-tier scrubbing cache. 300 GPU textures in VRAM for instant scrub (Tier 1), per-video last-frame cache for seek transitions (Tier 2), and a 900-frame RAM Preview with CPU/GPU promotion (Tier 3). When the cache is warm, scrubbing doesn't decode at all.
15 runtime dependencies. React/React DOM, Zustand, MediaBunny, mp4box, PlayCanvas / splat-transform helpers, dotLottie, HuggingFace Transformers, ONNX Runtime, SoundTouch, WebGPU types, plus an experimental FFmpeg WASM path. Everything else is custom-built from scratch: the WebGPU compositor, all 30 effect shaders, the keyframe animation system, the export engine, the audio mixer, the text renderer, the mask engine, the video scope renderers, the dock/panel system, the timeline UI, and the native shared 3D scene path. Zero runtime abstraction layers between your timeline and the GPU.
Nested composition rendering. Compositions within compositions, each with their own resolution. Rendered to pooled GPU textures with frame-level caching, composited in the parent's ping-pong pass, all in a single device.queue.submit().
On-device AI. SAM2 (Segment Anything Model 2) runs entirely in-browser via ONNX Runtime. Click to select objects in the preview, propagate masks across frames. No server, no API key, no upload. ~220MB model loaded on demand.
No Adobe subscription, no patience for cracks, and every free online editor felt like garbage. I wanted something that actually works: fast in the browser, GPU-first, built for real editing instead of templates, and open enough that AI can steer the timeline instead of just suggesting ideas.
The vision: an editor where AI can directly operate the tool. The built-in chat connects to OpenAI/Cloud or a local Lemonade Server and exposes 79 exported editing tools. External agents can steer the running editor over the local/native HTTP bridge, and in development the Vite bridge still exists too. Live outputs still matter too - I've been doing video art for 16 years, so multi-output routing was never optional.
Built with Claude as my pair-programmer. Every feature gets debugged, refactored, and beaten into shape until it does what I need. ~165k lines of TypeScript, ~2,700 lines of WGSL, and a Rust native helper for the stuff browsers still can't do cleanly.
MasterSelects is being built around the idea that AI should be able to do the edit, not just talk about it.
- Built-in editor chat: OpenAI/Cloud or local Lemonade chat, compact provider/model menus, project-saved system prompts, and direct access to 79 exported timeline/media/editing tools
- Local Lemonade provider: OpenAI-compatible Lemonade Server support for local chat models such as
gemma4-it-e2b-FLM; model discovery comes from/models, and the endpoint is restricted to loopback hosts - External agent bridge: Claude Code or any other local agent can drive the running editor via the Native Helper HTTP bridge, and in development the same tool surface is also available through the Vite bridge and
window.aiTools - AI video and image generation: Classic AI Video plus FlashBoard route through Kie.ai, hosted cloud, and PiAPI-backed catalogs depending on account and key setup
- Experimental multicam AI: Claude/Anthropic generates edit decision lists for the multicam workflow
- On-device AI: SAM2 segmentation in-browser via ONNX Runtime, MatAnyone2 via Native Helper, plus local Whisper transcription via Transformers.js
Example Native Helper bridge call:
curl -X POST http://127.0.0.1:9877/api/ai-tools \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <startup-token>" \
-d '{"tool":"_list","args":{}}'This requires the Native Helper to be running, a MasterSelects editor tab to be connected, and the helper startup token. The Vite /api/ai-tools bridge still exists in development, but it is now gated by a per-session token as well.
| Feature | Description |
|---|---|
| Multi-track Timeline | Cut, copy, paste, multi-select, JKL shuttle, nested compositions |
| 30 GPU Effects | Color correction, blur, distort, stylize, keying - all real-time |
| Video Scopes | GPU-accelerated Histogram, Vectorscope, Waveform monitor |
| Keyframe Animation | Bezier curves, copy/paste, tick marks, 5 easing modes |
| Vector Masks | Pen tool, edge dragging, feathering, multiple masks per clip |
| SAM2 Segmentation | AI object selection in preview - click to mask, propagate across frames |
| Transitions | Crossfade transitions with GPU-accelerated rendering (experimental) |
| AI Integration | Built-in OpenAI/Cloud or local Lemonade chat, 79 exported tool-callable edit actions, and local/native bridges for external agents |
| FlashBoard | Node-based AI canvas for text-to-video, image-to-video, and image generation |
| Multicam AI | Sync cameras, transcribe footage, and generate Claude-powered multicam EDLs (experimental) |
| Export Pipeline | WebCodecs Fast/Precise, FFmpeg intermediates, image/audio-only export, FCPXML, and project-persistent presets |
| Live EQ & Audio | 10-band parametric EQ with real-time Web Audio preview |
| Download Panel | YouTube, TikTok, Instagram, Twitter/X, Vimeo, and other yt-dlp-supported sites via Native Helper |
| Vector Animation | .lottie and Lottie JSON clips with bounce playback, render resolution overrides, keyframed state machines, and deterministic preview/export |
| Text & Solids | 50 Google Fonts, stroke, shadow, and solid color clips |
| Proxy System | GPU-accelerated proxies with resume and cache indicator |
| Output Manager | Multi-window outputs, source routing, corner pin warping, slice masks |
| Slot Grid | Resolume-style 12x4 grid with multi-layer live playback and slot-clip trims |
| Preview & Playback | RAM Preview, transform handles, multiple render targets |
| Project Storage | Local folders, raw media auto-copy, continuous save by default, interval mode, backups |
| Interactive Tutorial | Guided onboarding with animated Clippy mascot |
npm install
npm run dev # http://localhost:5173Requirements: Chrome 113+ with WebGPU support is the main target. Dedicated GPU recommended.
Firefox: project storage requires the Native Helper backend because Firefox does not support the File System Access API flow used by Chrome.
Linux: Enable Vulkan for smooth 60fps:
chrome://flags/#enable-vulkan
Cross-platform Rust companion app for the parts browsers still can't do well. Required for Firefox project storage and for yt-dlp-based downloads.
cd tools/native-helper
cargo run --release # WebSocket :9876, HTTP :9877| Capability | Details |
|---|---|
| Storage | Native project persistence backend for Firefox |
| AI Control | Local HTTP bridge for external agents to steer the running editor |
| Download | yt-dlp integration for YouTube, TikTok, Instagram, Twitter/X, Vimeo, and other supported sites |
Platforms: Windows, Linux, macOS. Building the Native Helper requires Rust. Downloads also require yt-dlp. See Native Helper docs for platform-specific setup.
MasterSelects is a local-first editor. Editing, rendering, caching, and most analysis stay in the browser unless you explicitly invoke an external provider or the Native Helper.
- API keys: stored in IndexedDB with per-browser Web Crypto encryption
- Native Helper: binds to
127.0.0.1only, requires a random startup Bearer token for HTTP and WebSocket - Dev bridge: Vite
/api/ai-toolsand local file routes require a per-session token and reject non-loopback origins - Lemonade local chat: endpoint is restricted to
localhost,127.0.0.1, or::1; Lemonade can suggest tool calls but execution still goes through the normal chat approval and dispatcher path - Local file access: restricted to explicit allowed roots (project root, temp, Desktop, Documents, Downloads, Videos)
- AI tool policy: external bridge calls run through caller restrictions and approval gates
- Secret handling: logs redact common secret/token patterns;
.keys.encexport disabled - CI checks: secret scanning, JS and Rust security audits, dedicated tests for bridge auth and file access policy
Known boundary: this is not perfect sandboxing. Same-user local processes, malicious browser extensions, and compromised same-origin code can still be dangerous. The goal is clear, test-covered local trust boundaries.
See Security.md for the full trust model and limitations.
This is alpha software. Features get added fast, things break.
- FFmpeg WASM export is still work in progress
- Multicam AI is experimental
- Transitions are experimental
- Firefox project storage requires the Native Helper backend
- Video downloads require Native Helper with yt-dlp installed
- Audio waveforms may not display for some video formats
- Very long videos (>2 hours) may cause performance issues
If something breaks, refresh. If it's still broken, open an issue.
- Frontend: React 19, TypeScript, Zustand, Vite 7.3
- Rendering: WebGPU + 2,700+ lines of WGSL shaders
- Video: WebCodecs, MediaBunny, mp4box, HTMLVideo fallback, and experimental FFmpeg WASM export path
- Audio: Web Audio API with 10-band live EQ, element-synced playback, drift correction, and waveform extraction
- AI: Built-in OpenAI/Cloud or local Lemonade editor chat with 79 exported tools, Native Helper HTTP bridge for Claude Code / external agents, Claude/Anthropic for experimental multicam EDLs, SAM2 via ONNX Runtime, MatAnyone2 via Native Helper, local Whisper via Hugging Face Transformers, and Kie.ai / hosted cloud / PiAPI-backed generation flows
- Native: Rust helper for Firefox storage backend, native decode/encode, and yt-dlp downloads
- Storage: File System Access API on Chrome, Native Helper backend on Firefox, IndexedDB, local project folders with raw media
| Key | Action |
|---|---|
Space |
Play/Pause |
J / K / L |
Reverse / Pause / Forward (shuttle) |
C |
Cut at playhead |
I / O |
Set in/out points |
Ctrl+C/V |
Copy/Paste clips or keyframes |
Shift+Click |
Multi-select clips |
Tab |
Toggle edit mode |
Ctrl+Z/Y |
Undo/Redo |
Ctrl+S |
Save project |
Detailed docs for each feature: docs/Features/
npm run dev # Dev server with HMR
npm run dev:changelog # Dev server with changelog dialog
npm run build # Production build (tsc + vite)
npm run build:deploy # Production build (vite only, skip tsc)
npm run lint # ESLint
npm run preview # Preview production build
npm run test # Run tests (vitest)
npm run test:security # Security-focused test suite
npm run test:watch # Run tests in watch mode
npm run test:ui # Run tests with UI
npm run test:coverage # Run tests with coverage
npm run test:unit # Run unit tests onlyProject Structure
src/
├── components/ # React UI
│ ├── timeline/ # Timeline editor (hooks/, components/, utils/)
│ ├── panels/ # Properties, Media, AI, Download, Export, Scopes, Transitions
│ ├── preview/ # Canvas + overlays + transform handles + SAM2 overlay
│ ├── outputManager/ # Multi-window output with slices
│ ├── export/ # Export dialog, codec selector, FFmpeg section
│ ├── dock/ # Panel/tab system
│ ├── common/ # Dialogs, tutorial, settings, shared components
│ └── mobile/ # Mobile-responsive layout
├── stores/ # Zustand state management
│ ├── timeline/ # Slices: track, clip, keyframe, mask, playback, selection, transitions, ...
│ └── mediaStore/ # Slices: import, folder, proxy, composition, slot, selection
├── engine/ # WebGPU rendering pipeline
│ ├── core/ # WebGPUContext, RenderTargetManager
│ ├── render/ # Compositor, RenderLoop, LayerCollector, NestedCompRenderer
│ ├── export/ # FrameExporter, VideoEncoder, ClipPreparation
│ ├── audio/ # AudioMixer, AudioEncoder, TimeStretch
│ ├── ffmpeg/ # FFmpegBridge, codecs
│ ├── pipeline/ # CompositorPipeline, EffectsPipeline, OutputPipeline, SlicePipeline
│ ├── texture/ # TextureManager, ScrubbingCache, MaskTextureManager
│ ├── managers/ # CacheManager, ExportCanvasManager, OutputWindowManager
│ ├── analysis/ # Histogram, Vectorscope, Waveform scopes
│ ├── video/ # VideoFrameManager
│ ├── stats/ # PerformanceStats
│ └── structuralSharing/ # SnapshotManager for undo/redo
├── effects/ # 30 GPU effects (color/, blur/, distort/, stylize/, keying/)
├── transitions/ # Transition definitions (crossfade)
├── services/ # Audio, AI, Project, NativeHelper, Logger, LayerBuilder, MediaRuntime
│ ├── aiTools/ # 79 exported AI tool definitions + handlers
│ ├── sam2/ # SAM2 model manager + service
│ ├── project/ # Project persistence, save/load
│ ├── nativeHelper/ # Native decoder + WebSocket client
│ ├── layerBuilder/ # Layer building + video sync
│ ├── mediaRuntime/ # Media runtime bindings + playback
│ ├── vectorAnimation/ # Lottie metadata sniffing + runtime canvas playback
│ └── export/ # FCPXML export
├── shaders/ # WGSL (composite, effects, output, optical flow, slice)
├── hooks/ # React hooks (useEngine, useGlobalHistory, useMIDI, useTheme)
├── utils/ # Keyframe interpolation, mask renderer, file loader
├── types/ # TypeScript type definitions
├── workers/ # Transcription worker
└── test/ # In-browser test components
tools/
├── native-helper/ # Rust binary (FFmpeg + yt-dlp bridge)
│ └── src/ # WebSocket server, decode/encode sessions
├── ffmpeg-build/ # FFmpeg build scripts
├── ffmpeg-wasm-build/ # FFmpeg WASM build configuration
└── qwen3vl-server/ # Qwen3 VL server for scene description
License Scan (FOSSA)
The linked FOSSA report tracks direct and transitive dependencies across npm, Cargo, and pip. The current npm runtime surface in package.json has 15 direct runtime dependencies.
| Category | Count | Status |
|---|---|---|
| License Issues | 35 flagged | All reviewed — no violations |
| Vulnerabilities | 6 | All in dev-dependencies, fixable via npm audit fix |
| Outdated Deps | 4 | Non-critical |
Flagged licenses (all compliant):
| Package | License | Why it's OK |
|---|---|---|
soundtouch-ts |
LGPL-2.1 | Used as unmodified npm dependency |
sharp / libvips (15 platform binaries) |
LGPL-3.0 | Used as unmodified prebuilt binary |
mediabunny |
MPL-2.0 | Used as unmodified npm dependency |
torch, pillow |
BSD/PIL | Python tooling only (tools/qwen3vl-server), not shipped |
Cargo crates (r-efi, ring, rustix, wit-bindgen, ...) |
Apache-2.0 / MIT | Standard Rust ecosystem, no copyleft issues |
No source code of any dependency has been modified. No GPL/AGPL dependencies. All copyleft packages (LGPL, MPL) are used strictly as libraries via their published APIs.
MIT License · Built by a video artist who got tired of waiting for Adobe to load
