Modulr is a browser-based, node-driven music creation tool. Build a patch by wiring synth, effect, and utility nodes in a visual graph, then play it in real time using the Web Audio API. It is designed to feel like a modular hardware synth rack, but with an n8n-style node editor, presets, and reusable macro instruments.
- Node-based patching with React Flow canvas
- Real-time audio synthesis in the browser (no server audio)
- Source nodes: Oscillator, FM Synth, Noise, Karplus-Strong, Drum Synth, Granular
- Effects: Filter, Delay, Reverb, Distortion/Waveshaper
- Utility and control: Amp, LFO, Sequencer, Master Out
- Macro instruments: save a selected sub-graph as a reusable instrument
- Preset library and local patch save/load
- Keyboard shortcuts:
Spaceplay/stop,Deleteremove selected,Ctrl/Cmd+Zundo
- Design synth patches by connecting nodes (sources, effects, utilities)
- Play/stop the audio engine and adjust BPM
- Save and load patches locally in the browser
- Create reusable macro instruments from a selected sub-graph
- Browse and load factory presets
- Build rhythmic patterns with the sequencer node
- Frontend: React 19, Vite, React Flow, Zustand, Tailwind CSS
- Audio: Web Audio API
- Backend: Express (development server + production static serving)
- Data: LocalStorage (patches, instruments)
- Frontend-first: all synthesis and sequencing happen client-side.
- Express server: serves the Vite app in development and static assets in production.
- Persistence: patches and instruments are stored in
localStorageundermodulr-patchesandmodulr-instruments. - State sync: Zustand store mirrors React Flow state and drives the audio engine.
- Audio Engine (
client/src/audio/engine.ts): creates Web Audio nodes, manages connections, and handles macro instruments. - State Store (
client/src/store/useStore.ts): React Flow state, patch history/undo, persistence, and audio sync. - Node Components (
client/src/components/nodes/): UI and controls for each node type. - Presets (
client/src/data/presets.ts): factory patches and categories. - Canvas / UI (
client/src/pages/Home.tsx): main editor, transport, menus, and user interactions. - Server (
server/): Express app with Vite middleware for dev and static serving in production.
- Sources: Oscillator, FM Synth, Noise, Karplus-Strong, Drum Synth, Granular
- Effects: Filter, Delay, Reverb, Distortion/Waveshaper
- Utility: Amp, Master Out
- Modulation/Control: LFO, Sequencer
Macro instruments let you turn a selection of nodes into a reusable instrument node.
- Select 2+ nodes, then save as an instrument with a name, color, and exposed parameters.
- Internals are stored with
macroId::nodeIdIDs to keep them grouped. - Input/output gain nodes are created to manage external routing.
- Stored in
localStorageundermodulr-instrumentsand listed under the “Instruments” section in Add Node.
- Effects like Delay and Reverb use input/output node pairs for dry/wet routing.
connect()routes via output nodes:getOutputNode(source) -> getInputNode(target).- Sequencer uses a scheduling loop with lookahead for timing stability.
client/src/audio/engine.ts- Core audio engine (Web Audio API)client/src/store/useStore.ts- Zustand store (graph + audio state)client/src/pages/Home.tsx- Main canvas with React Flowclient/src/components/nodes/- All node type componentsclient/src/components/nodes/MacroNode.tsx- Macro/instrument node UIclient/src/components/InstrumentDialog.tsx- Save-as-instrument dialogclient/src/data/presets.ts- Factory preset patchesclient/src/index.css- UI theme tokens
- Added Macro Instruments (save selected nodes as reusable instruments)
- Added Karplus-Strong string synthesis node
- Added Drum Synth node (kick/snare/hihat/clap/tom)
- Added Distortion/Waveshaper effect node
- Added Granular Synth node with sample upload
- Added Ctrl/Cmd+Z undo (50-step history)
- Improved trackpad zoom and added more node types (Delay, Reverb, Noise, LFO)
- Requirements: Node.js 18+ recommended
npm install
npm run devOptional:
npm run dev:clientfor Vite onlynpm run buildthennpm run startfor production
npm run dev- Express + Vite dev servernpm run dev:client- Vite dev server onlynpm run build- Build client and bundle server todist/index.cjsnpm run start- Run production servernpm run check- TypeScript checknpm run db:push- Push schema to Postgres (requiresDATABASE_URL)
PORT- Server port (default:5000)DATABASE_URL- Required only fornpm run db:push
client/- React app, UI, and audio engineclient/src/audio/- Web Audio engineclient/src/components/nodes/- Node UIsclient/src/pages/Home.tsx- Main canvasclient/src/store/useStore.ts- Zustand state and persistenceserver/- Express server + Vite dev integrationshared/- Shared schema (Drizzle + Zod)
- Audio starts only after user interaction (browser autoplay policy).
- Saved patches and instruments are per-browser and stored locally.
Contributions are welcome, especially new node types, UI improvements, and audio engine enhancements.
- Implement audio behavior in
client/src/audio/engine.tsand add a node handler with input/output nodes. - Add default parameters in
client/src/store/useStore.tsunderdefaultNodeData. - Create the node UI in
client/src/components/nodes/and wire controls to the store. - Register the node in
nodeTypesandNODE_CATALOGinclient/src/pages/Home.tsx. - Optional: add example patches in
client/src/data/presets.ts.
- Create a branch.
- Make focused changes with clear naming.
- Run
npm run checkbefore opening a PR. - Include a short description and screenshots/gifs if UI changes are involved.
MIT
