# signal: npm start errors on a fresh clone until the build has run once

> A web music sequencer that lives in a turbo monorepo with three deployment targets and one maintainer. The first run is documented as a failure, the package manifest is private at 0.0.1, and the Docker path skips the build entirely.

**ryohey/signal** — Online MIDI Editor: signal

- Repository: https://github.com/ryohey/signal
- Website: https://signalmidi.app
- Stars: 2,387 · Forks: 256
- Language: TypeScript
- License: MIT
- Published: 2026-09-28 · Updated: 2026-09-28 · Language: en
- Canonical page: https://hysenlabs.com/projects/ryohey-signal

## The setup guide tells you the first run will error

The running section carries a note before the command: the first time you run it, you will get a build error, so please run npm run build once before running npm start. That is a documented failure rather than a broken instruction, and the manifest explains why. start is not a production start, it is turbo run dev --parallel, a development task fanned out across the workspaces. The production path is separate: build runs build:app, which is turbo build followed by copying app/dist into dist with cpx, and serve runs npx http-server dist. So on a clone with nothing built, the dev task has no output to serve, and the documented workaround is to produce that output once by hand. The clone itself is two commands, git clone of the repository URL and cd signal, followed by npm install.

## The Docker route exists so you never run npm install

The Docker section exists to remove the papercut above. Its note says that with docker, npm install and npm run build will not be necessary, and that you only need docker, then the repository clone, then one command:

```sh
docker compose up
# or
docker compose up -d
```

The compose file keeps it to one service named app, built from the current directory, publishing port 3000 to port 3000 with NODE_ENV set to production and PORT set to 3000. The Dockerfile is two stages on a node image chosen by an ARG defaulting to lts-alpine. The builder copies the tree into /code and runs npm install and npm run build with an npm cache mounted at /root/.npm. The runner installs serve@latest globally, copies the built dist out of the builder into /web, exposes 3000 and starts serve. That unpinned serve@latest is the one dependency in the image that resolves to whatever is newest at build time.

## Three hosting targets sit in one tree

The repository carries configuration for three different ways of putting the app online. Firebase is the most complete: firebase.json, a .firebaserc, firestore.rules, firestore.indexes.json and a functions/ directory, with scripts for firebase, firebase:deploy and an emulator start that builds the functions first and then runs firebase emulators:start. Vercel has a single vercel.json. Electron has its own directory with a dev script that runs the app workspace and the electron workspace concurrently, a build script that removes electron/dist_renderer and refills it from app/dist, and packaging targets for darwin, for win, and for the Mac App Store through make:mas. On top of that there is the Docker route. Four ways to run one editor, and the README documents only the first and the last.

## The environment template is six empty Firebase keys

.env.example holds six variable names with nothing after the equals sign: FIREBASE_API_KEY, FIREBASE_AUTH_DOMAIN, FIREBASE_PROJECT_ID, FIREBASE_STORAGE_BUCKET, FIREBASE_MESSAGING_SENDER_ID and FIREBASE_APP_ID. They are the standard client configuration set for a Firebase web app, and the file is a template rather than a working configuration. So anyone intending to use the Firebase path has to supply a project of their own before those variables mean anything, while the Docker path needs none of them, since the compose file sets only NODE_ENV and PORT. The presence of .gitignore, .dockerignore and .gitmodules alongside the template tells you the build contexts are kept separate, and the submodule file means part of the tree is fetched rather than authored here.

## The manifest is private, versioned 0.0.1, and describes two platforms

The package manifest says private true, so the package is not published, and its version is 0.0.1, which is a placeholder rather than a release number. There are no GitHub releases either. The description field reads A friendly music sequencer application for OS X and Windows, while the README describes cross platform use through web technologies and lists cross platform compatibility as the first goal. Both statements describe the same project from different ends: the browser app is the portable surface, and the Electron packaging targets are the two desktop systems, since the scripts cover darwin, win and the Mac App Store and nothing else. The homepage field points at the GitHub repository rather than the app, while the metadata homepage in the project description points at the app.

## No effects and basic sound quality are stated as the design

The concepts section is unusually direct about what the tool will not do. signal is positioned as a complement to a Digital Audio Workstation rather than a replacement, and the intended use is the initial stage of composition and sketching, laying down ideas quickly. Three limitations are named as intentional: basic sound quality, with simplicity preferred over high quality sound production; no effects, with sound effects excluded to keep the creation process short; and a lightweight design optimised for minimal resource usage. Two goals sit above that list, a simple user interface and MIDI compatibility. Read together, the page is a scope statement, and it also tells a user what to reach for when the sketch has to become a finished track.

## One maintainer, three support paths, no releases

The contribution section is written in the first person by a single author, who describes signal as a personal project. Three paths are offered. Bugs go to GitHub Issues, with a request for reports that identify and resolve problems. A Discord community is linked for mutual support and discussion of music production. And GitHub Sponsors is offered for financial support, with the note that even the smallest contribution helps. None of that is a support commitment with a response time behind it, and the repository has no GitHub releases, so the only version marker available is the commit history, where the last recorded push is dated 2026-08-26. The application itself is reachable at the edit path of the hosted site, which is the intended way to try it before cloning anything.

## The workspace is app plus packages, wired through turbo and biome

The build system is a monorepo. The workspaces field names app and packages/*, and turbo drives both the dev servers and the tests: start is turbo run dev --parallel and test is turbo test. Everything else routes through one of those two. Linting and formatting belong to biome, pinned at 2.4.4, with separate lint, format, format:check and check scripts, so a contributor has one tool to satisfy rather than an eslint config and a prettier config. The rest of the tree is the usual set of scaffolding: a scripts/ directory, a .vscode/ directory, a CLAUDE.md, a turbo.json and a package-lock.json. The build:app script is the hinge, because it is what produces the dist directory that both the local serve script and the Docker image copy.

## Conclusion

Use signal when you want to sketch a MIDI idea in a browser and get to the editor without installing a desktop sequencer, and when you are willing to treat it as the sketching tool its own concept page says it is, with no effects and basic sound quality. Check three things before you build on it. The first run fails by design in the documentation, so npm run build has to precede npm start, and the Docker route exists precisely to avoid that. The package is marked private at version 0.0.1 with no GitHub releases, so there is no artifact to pin and no changelog to read for behaviour changes. And it is one person's project, so the GitHub Issues tracker is the only support channel that is guaranteed to exist.

## FAQ

### How do I run signal locally for the first time?

Clone the repository, cd signal, run npm install, and then run npm run build once before npm start. The application is then served on http://localhost:3000.

### What does running signal with Docker require?

Only docker. The documentation says npm install and npm run build are not necessary in that case, and the app comes up on http://localhost:3000 after docker compose up, or docker compose up -d.

### Does signal include effects or high quality sound?

No. The concepts section lists basic sound quality, no effects and a lightweight design as intentional limitations, and positions signal as a sketching tool rather than a replacement for a Digital Audio Workstation.

### What does the signal package manifest say about its version and platforms?

Version 0.0.1, marked private, with the description A friendly music sequencer application for OS X and Windows. The Electron packaging scripts cover darwin, win and the Mac App Store.

### How do I report a bug in signal?

Through GitHub Issues. A Discord community and GitHub Sponsors are also linked from the README, and the project is described as a personal project.

### Are there GitHub releases for signal?

No, the repository has no GitHub releases and the manifest version is 0.0.1. The last recorded push is dated 2026-08-26.

## Sources

- [Issues](https://github.com/ryohey/signal/issues)
- [License: MIT](https://github.com/ryohey/signal/blob/main/LICENSE)
- [Project website](https://signalmidi.app)
- [README](https://github.com/ryohey/signal/blob/main/README.md)
- [ryohey/signal on GitHub](https://github.com/ryohey/signal)

---

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