# Web Synth: a browser DAW that runs Rust and Faust on the audio thread

> Web Synth is a browser based audio synthesis and music production platform that combines traditional DAW features with modular patching, compiling synthesizers, effects and audio nodes from Rust and Faust into WebAssembly and running them on the dedicated audio thread. It has a working FM synthesizer, a MIDI editor, loopers and a graph editor, and it runs entirely in the browser.

**Ameobea/web-synth** — Browser-based DAW and audio synthesis platform with dozens of effects, synths, and modules

- Repository: https://github.com/Ameobea/web-synth
- Website: https://synth.ameo.dev
- Stars: 582 · Forks: 33
- Language: TypeScript
- License: NOASSERTION
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/ameobea-web-synth

## Why the audio is written in Rust and compiled to WebAssembly

Web Synth is a browser based audio synthesis, music production and sound experimentation platform, and the design decision that defines it is where the audio code actually runs.

The tool makes extensive use of modern web technologies including Web Audio, WebAssembly, WebGL, WebMIDI, SharedArrayBuffer and AudioWorkletProcessor. It supports high performance and low latency realtime audio generation by compiling code for synthesizers, effects and other audio nodes from Rust and other specialised languages into WebAssembly and running it on the dedicated audio thread. The claim that follows is near-native performance and jank-free playback.

That is the whole point of the architecture, and it is worth being clear about what it buys and what it costs. A JavaScript audio node running on the main thread competes with layout, garbage collection and everything else the page is doing, and the jitter is audible. A WebAssembly module inside an AudioWorkletProcessor does not, because the audio thread is reserved for the graph. The price is a compilation step, a build toolchain and a boundary between the graph and the modules.

The consequence is that Web Synth requires a modern browser. The readme says it will technically load on mobile devices and phones, but the UI is not optimised for mobile use at this time. That is an honest limitation stated plainly rather than hidden.

The three hosted entry points make the scope obvious. The full application is at synth.ameo.dev, there is a standalone FM synthesizer demo at synth.ameo.dev/fm.html, and the documentation and development notes are at synth.ameo.dev/docs/. The separate FM demo is a good sign of engineering taste, since it isolates one part of the system into something you can open in a browser and use immediately.

## The WebAudio graph is the application state

The design section describes an architecture where the signal graph is not just a view but the state of the program.

The tool is built on top of the WebAudio API and makes use of it for all audio processing. The WebAudio graph is the backbone of everything, and every piece of audio processing code exists as a node within it. These nodes are created as different modules within the application and can be connected together using a built-in graph editor.

The engine's responsibilities are listed precisely, and they are the unglamorous ones that decide whether such a system is usable. It has support for handling de-initialization and initialization of nodes, resolving connections, handling input and output shapes changing, and serializing and deserializing on page load and unload.

That last one connects to how state is stored. The whole application state is serialized to the browser's local storage every time the tab is closed, and automatically reloaded when the tab is opened again. Saving and loading is as simple as creating or loading a JSON blob representing the state of localStorage. The stated goal, which the author says is mostly but not completely realized, is that refreshing the page should bring you back to the exact state you were in before, with no user intervention.

The admission that the goal is not fully met is worth keeping in mind, because a modular patcher with a deep graph is exactly the kind of application where a partial serialisation failure is easy to hit. The architecture makes the state explicit and inspectable, which is the right foundation, but a JSON blob in local storage has a size limit and a schema that can change underneath it.

## The feature list is a list of instruments, not a list of settings

The notable features read like a list of instruments rather than a list of preferences, and that tells you what kind of tool this is.

The centrepiece is a versatile 8-operator polyphonic FM synthesizer. It supports many primitive waveforms as well as loading wavetables from WaveEdit or other sources, and it contains a number of built-in effects from basics like a bitcrusher and filters through to OTT-style multiband compression and wavefolding. It is highly modulatable and patchable with sample-level parameter automation via other modules or built-in per-voice envelope generators.

Then there is a fully functional MIDI editor, with MIDI file import and export, multi-note selection and editing, recording live from a keyboard or other input source, and live playback and preview. Two programmable loopers for samples and MIDI sit alongside it.

The third group is the one that makes the tool unusual, and it is the dynamic compilation of DSP code written in Faust and Soul via WebAssembly. The stated rationale is that this facilitates infinite custom effects using existing code with minimal or no changes required, and that the parameters are fully integrated into the web synth patching system, so they can be modulated by other components or controlled live by an auto-generated user interface.

The rest of the list covers the modular vocabulary: LFOs, random voltage sources and quantizers, visualisers including an oscilloscope and a spectrum analyser, support for building custom user interfaces with many input types and markdown notes, and support for hardware MIDI keyboards and controllers through WebMIDI. The readme closes with a list of other tools, a visual filter designer, a granular synthesizer, delays and signal debuggers.

A preset and composition sharing and loading system for many of the components sits across all of this, and it is the feature that turns a private instrument into a community one.

## The build needs Rust nightly, binaryen and a Faust compiler service

The development setup is a long toolchain list, and it is the part of the project most likely to cost you an afternoon.

The readme notes first that the docs might be somewhat out of date, and that you should check the GitHub Actions CI script and the Justfile in the project root for details. That warning is worth heeding, because the list that follows is a Rust toolchain plus several separate compilers.

The Rust programming language is required, and specifically the nightly version. The wasm32-unknown-unknown target is needed, installed with rustup target add. The wasm-bindgen-cli is installed with cargo install. The wasm-opt tool comes from cloning the WebAssembly binaryen repository and following its install instructions. NodeJS and Yarn are needed for the front end, and the Just command runner is installed with cargo install just.

Two of the requirements are conditional and point at the service architecture. Faust code support needs go installed, and running the Web API backend, which handles presets, composition sharing and a few other things, needs a MySQL database and the Diesel ORM command line tool installed with the mysql feature.

The environment example shows what the backend and compiler services expect. There is a DATABASE_URL in MySQL form, a ROCKET_DATABASES entry with a web_synth database and a timeout, a FAUST_COMPILER_SERVICE_NAME and a FAUST_COMPILER_IMAGE_NAME pointing at a container image, a BACKEND_BASE_URL, and a FAUST_COMPILER_ENDPOINT, with commented local alternatives for the backend on port 7467 and the compiler on port 4565. That tells you the Faust compilation is a separate service rather than something in the browser, which is a significant architectural fact: a piece of DSP code written in Faust is compiled server side and the resulting WebAssembly is what runs.

## Two commands once the toolchain is in place

Once everything is installed, the build is a Just task.

You can build the project by running just build-all, to create an optimized production deployment, or just run, to start a local webserver on port 9000 for development that automatically hot-reloads when the JS and TS code is changed.

The hot reload behaviour is the detail that matters for a project with this much compiled code. A change to the TypeScript front end is picked up automatically, but a change to a Rust module means recompiling to WebAssembly, running wasm-bindgen and then wasm-opt, and the readme describes those tools as being there for compiling, transforming and optimising the WebAssembly blobs that are created as output for the Rust application. So the edit loop is fast on one side of the codebase and slow on the other, which is the normal shape for a project that mixes a hot-reloaded front end with a compiled audio engine.

The package.json shows the same split at the JavaScript level, with a start script running vite, a build script that clears the dist directory and sets the backend base URL before building, and a separate build-headless script that builds with a different Vite config and copies the wasm and js files from public into the headless output directory. The headless build is for the FM synthesizer demo page, which is the standalone fm.html in the repository root.

The rest of the layout follows the architecture. The engine/ directory holds the audio engine, src/ is the Svelte front end, faust-compiler/ is the Faust compilation service, backend/ is the Rust web API, cypress/ and test/ hold the two test suites, and docs/ the documentation. There is a Justfile at the root, a.env.example, a vite.config.mts and a vite.config.headless.mts for the two build targets, and a.dockerignore.

The licence is a custom one that GitHub could not classify, with a LICENSE file at the root, and the repository is not archived with the last push on 2026-08-13.

## Conclusion

Web Synth suits a musician or sound designer who wants to patch a modular style signal chain in a browser, or a developer who wants to see a Rust to WebAssembly audio pipeline run on the audio thread with sample accurate scheduling. It does not suit a mobile user, since the readme says the interface is not optimised for mobile, and it does not suit someone who needs the desktop DAW's file format compatibility. Before building it, install the nightly Rust toolchain with the wasm32 target, wasm-bindgen-cli and wasm-opt, then run just run for a local server on port 9000, and check the Justfile, which the readme says is the more current source of build instructions.

## FAQ

### What is Web Synth?

It is a browser based audio synthesis, music production and sound experimentation platform with features of traditional DAWs plus modular style patching, dynamic custom code and live looping. It has a full application at synth.ameo.dev, a standalone FM synthesizer demo at synth.ameo.dev/fm.html, and documentation at synth.ameo.dev/docs.

### How does Web Synth achieve low latency audio?

It compiles code for synthesizers, effects and other audio nodes from Rust and other specialised languages into WebAssembly and runs it on the dedicated audio thread, which it says offers near-native performance and jank-free playback. It uses Web Audio, WebAssembly, WebGL, WebMIDI, SharedArrayBuffer and AudioWorkletProcessor.

### Which languages can I write DSP code in for Web Synth?

Faust and Soul, compiled via WebAssembly. The parameters are integrated into the patching system so they can be modulated by other components or controlled live by an auto-generated user interface, and existing code can be reused with minimal or no changes.

### What do I need to build Web Synth from source?

The nightly Rust toolchain with the wasm32-unknown-unknown target, wasm-bindgen-cli, wasm-opt from the binaryen repository, NodeJS and Yarn, and the Just command runner. Faust support needs go, and running the backend that handles presets and composition sharing needs a MySQL database and the Diesel CLI. Then just build-all or just run for a dev server on port 9000.

## Sources

- [Ameobea/web-synth on GitHub](https://github.com/Ameobea/web-synth)
- [Issues](https://github.com/Ameobea/web-synth/issues)
- [Project website](https://synth.ameo.dev)
- [README](https://github.com/Ameobea/web-synth/blob/main/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/ameobea-web-synth
