How ryohey/signal works
1. This is a TypeScript monorepo for a MIDI sequencer product called signal, split into a desktop/web editor, a public community site, shared domain libraries, and Firebase-backed cloud services. The main architectural boundary is between UI surfaces and shared music/domain logic.
2. The core musical model lives in packages/core. It owns songs, tracks, beats, selections, transforms, MIDI conversion, and command services. This package is the authoritative domain layer used by both the editor and the community site, so most editing behavior is expressed as operations over this shared model rather than duplicated UI logic.
3. The main editing application is app/. Its React UI is organized around feature-heavy editor panes: piano roll, tempo graph, arrange view, track list, control/velocity editors, transport, dialogs, and toolbars. The app is the interactive sequencer where note entry, selection, quantization, track management, and transport controls all converge.
4. State management in the editor is centralized through MobX-style stores under app/src/stores plus hooks in app/src/hooks. RootStore, SongStore, SoundFontStore, and MIDI device stores sit underneath view-specific hooks such as usePianoRoll, useTrackList, useTempoEditor, and usePlayer, which expose store state and commands to individual components.
5. Editing interactions are built around a gesture system. The piano roll, arrange view, control pane, and tempo graph each have their own mouse/gesture handlers for drawing, dragging, selection, scroll, and pencil tools. This makes pointer input a first-class subsystem rather than just component-local event handling.
6. Rendering is split between standard React UI and GPU/canvas-backed editor surfaces. The piano roll, arrange view, control graphs, and tempo graph use dedicated canvas or WebGL-like nodes/shaders for grids, notes, selection overlays, cursor lines, and velocity visualization. That separation matters because the interactive timeline views are not purely DOM-driven.
7. Playback and MIDI I/O are handled as a service layer rather than inside the UI. packages/player contains the audio/MIDI scheduler and soundfont synth, while app/src/services contains MIDI input/output, monitoring, recording, clipboard, autosave, and IndexedDB persistence. The editor therefore flows from user edits to song state, then into playback scheduling and optional MIDI hardware/output.
8. Persistence is multi-tiered: local autosave uses IndexedDB, while cloud song data is abstracted through repository interfaces in packages/api and concrete app services. The editor can save/load locally, sync to cloud files, and export MIDI/audio-related artifacts, so data flows both to local browser storage and to backend repositories.
9. Firebase is the main cloud boundary. The repository includes Firebase Auth, Firestore rules/indexes, hosting config, and Cloud Functions. packages/api defines repository contracts for cloud songs, song data, MIDI data, and users; functions/ provides the backend implementation, while app/src/firebase and the auth/community components handle client-side sign-in and identity.
10. The repo also ships a separate public/community experience in packages/community. This is a React app for browsing users, songs, recent activity, sharing, and profile pages. It reuses the same Firebase auth and shared song abstractions, but its concern is discovery and social presentation rather than editing.
11. Desktop packaging is provided by electron/. Electron wraps the web app with a main process, preload bridge, IPC, custom menu, auth helpers, and native file/system access. This creates a second runtime boundary: the same editor code can run in the browser, but Electron unlocks desktop capabilities such as native dialogs, filesystem integration, and bundled soundfonts.
12. Cross-cutting shared packages support the whole system: packages/dialog-hooks for modal state, packages/firebaseui-web-react for auth UI, and common utilities/types across the apps. Build tooling is a monorepo setup with Turbo, Vite, Vitest, and Electron Forge, while deployment targets include web hosting plus the Electron desktop bundle.
Main entry points: index.ts Core domain · RootStore.ts Editor state · repositories.ts App services · index.tsx Community app
Components 18
Editor app
React editor UI, stores, gestures, and canvas-backed sequencing views.
- App shell · Entry points, routing, auth, and global app composition.
app/src/components/App/App.tsx - Editor views · Piano roll, arrange, tempo, control, track list, and transport surfaces.
app/src/components/PianoRoll/PianoRoll.tsx - Canvas layers · Timeline rendering layers for notes, grids, selections, and cursor overlays.
app/src/components/PianoRoll/PianoRollCanvas/PianoRollCanvas.tsx - Gestures · Drag, pencil, scroll, and selection interaction handlers across editor surfaces.
app/src/components/PianoRoll/MouseHandler/useNoteMouseGesture.ts - Editor state · Central MobX-style stores and view hooks that coordinate editor state and commands.
app/src/stores/RootStore.ts - App services · Autosave, clipboard, MIDI I/O, IndexedDB storage, and repository adapters.
app/src/services/repositories.ts - Player runtime · Playback, MIDI scheduling, soundfont synthesis, and audio rendering.
packages/player/src/Player.ts
Shared domain
Authoritative music model, commands, and MIDI conversion shared by UI surfaces.
- Core domain · Songs, tracks, selections, transforms, commands, and MIDI conversion.
packages/core/src/index.ts - Song model · Canonical song aggregate and factory logic for shared musical state.
packages/core/src/entities/song/Song.ts - Track model · Track events, validation, identification, and track-level transformations.
packages/core/src/entities/track/Track.ts - Commands · Command services for arrange, control, conductor, and track mutations.
packages/core/src/commands/CommandService.ts - MIDI conversion · Raw event conversion, note assembly, and song export/import helpers.
packages/core/src/midi/midiConversion.ts
Cloud backend
Firebase-backed repositories, auth boundary, and server implementation.
- API contracts · Repository interfaces for cloud songs, MIDI data, and users.
packages/api/src/index.ts - Cloud functions · Server-side implementation for Firebase-backed application services.
functions/src/index.ts - Firebase client · Client-side Firebase initialization for auth and cloud access.
app/src/firebase/firebase.ts
Community site
Public discovery and profile experience built on shared song abstractions.
- Community app · Browsing, profiles, sharing, and recent activity for public song discovery.
packages/community/src/index.tsx - Community state · Auth, song, and root stores driving the public community experience.
packages/community/src/stores/RootStore.ts
Desktop runtime
Electron packaging, IPC bridge, and native desktop capabilities.
- Electron shell · Main process, preload bridge, menus, IPC, and native system integration.
electron/src/index.ts
Connections 22
- App shell → Editor views: composes · The app shell hosts the main editor panes and navigation.
- Editor views → Canvas layers: renders · Editor panes rely on canvas-backed timeline layers for note and selection display.
- Editor views → Gestures: handles input · Interactive panes delegate pointer interaction to gesture handlers.
- Gestures → Editor state: updates · Gestures dispatch editing actions through shared stores and hooks.
- Editor state → Core domain: commands · State layer drives song mutations through the shared domain model.
- App services → API contracts: implements · App services adapt repository interfaces for local and cloud persistence.
- App services → Firebase client: uses · Cloud-facing services use Firebase client initialization and auth state.
- Editor state → App services: persists · Stores coordinate autosave, clipboard, MIDI, and repository operations.
- Editor state → Player runtime: plays back · Editor state feeds scheduler and synth services for transport and monitoring.
- Player runtime → Core domain: consumes · Playback translates shared song and event models into scheduled audio/MIDI output.
- Core domain → Song model: owns · The core package centralizes the canonical song aggregate.
- Core domain → Track model: owns · Track semantics and validation live in the shared domain.
- Core domain → Commands: exposes · Command services define editing operations over the song model.
- Core domain → MIDI conversion: converts · MIDI import/export is part of the authoritative domain layer.
- Cloud functions → API contracts: implements · Backend functions realize the repository contracts used by the client.
- Community app → Community state: drives · The community UI is state-managed through its root stores.
- Community state → API contracts: reads · Community features depend on the same repository abstractions for songs and users.
- Community app → Firebase client: authenticates · Public pages use Firebase auth for sign-in and identity.
- Electron shell → App shell: hosts · Electron wraps the web editor in a desktop runtime.
- Electron shell → Player runtime: enables · Desktop packaging provides native access for bundled playback assets and system integration.
- Electron shell → App services: bridges · IPC and preload APIs extend app services with desktop capabilities.
- Community app → Core domain: shares · Community features reuse the shared song model and related abstractions.