# ryohey/signal architecture

> Architecture diagram of the GitHub repository ryohey/signal, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-06-24). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/ryohey/signal
- Repository: https://github.com/ryohey/signal

## Overview

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: [`packages/core/src/index.ts`](https://github.com/ryohey/signal/blob/main/packages/core/src/index.ts) (Core domain), [`app/src/stores/RootStore.ts`](https://github.com/ryohey/signal/blob/main/app/src/stores/RootStore.ts) (Editor state), [`app/src/services/repositories.ts`](https://github.com/ryohey/signal/blob/main/app/src/services/repositories.ts) (App services), [`packages/community/src/index.tsx`](https://github.com/ryohey/signal/blob/main/packages/community/src/index.tsx) (Community app)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_ui_app["Editor app"]
  node_app_shell["App shell<br/>react shell<br/>[App.tsx]"]
  node_editor_views["Editor views<br/>editor panes<br/>[PianoRoll.tsx]"]
  node_editor_canvas["Canvas layers<br/>gpu canvas"]
  node_gesture_handlers["Gestures<br/>pointer input"]
  node_editor_state["Editor state<br/>stores/hooks<br/>[RootStore.ts]"]
  node_app_services["App services<br/>persistence/io<br/>[repositories.ts]"]
  node_player_runtime["Player runtime<br/>audio scheduler<br/>[Player.ts]"]
end

subgraph group_shared_core["Shared domain"]
  node_core_domain["Core domain<br/>music model<br/>[index.ts]"]
  node_core_song["Song model<br/>domain entity<br/>[Song.ts]"]
  node_core_track["Track model<br/>domain entity<br/>[Track.ts]"]
  node_core_commands["Commands<br/>domain services<br/>[CommandService.ts]"]
  node_core_midi["MIDI conversion<br/>midi pipeline<br/>[midiConversion.ts]"]
end

subgraph group_cloud_backend["Cloud backend"]
  node_api_contracts["API contracts<br/>repo interfaces<br/>[index.ts]"]
  node_cloud_functions["Cloud functions<br/>firebase backend<br/>[index.ts]"]
  node_firebase_client["Firebase client<br/>auth/db client<br/>[firebase.ts]"]
end

subgraph group_community["Community site"]
  node_community_app["Community app<br/>public react app<br/>[index.tsx]"]
  node_community_store["Community state<br/>stores<br/>[RootStore.ts]"]
end

subgraph group_desktop["Desktop runtime"]
  node_electron_shell["Electron shell<br/>desktop host<br/>[index.ts]"]
end

node_app_shell -->|"composes"| node_editor_views
node_editor_views -->|"renders"| node_editor_canvas
node_editor_views -->|"handles input"| node_gesture_handlers
node_gesture_handlers -->|"updates"| node_editor_state
node_editor_state -->|"commands"| node_core_domain
node_app_services -->|"implements"| node_api_contracts
node_app_services -->|"uses"| node_firebase_client
node_editor_state -->|"persists"| node_app_services
node_editor_state -->|"plays back"| node_player_runtime
node_player_runtime -->|"consumes"| node_core_domain
node_core_domain -->|"owns"| node_core_song
node_core_domain -->|"owns"| node_core_track
node_core_domain -->|"exposes"| node_core_commands
node_core_domain -->|"converts"| node_core_midi
node_cloud_functions -->|"implements"| node_api_contracts
node_community_app -->|"drives"| node_community_store
node_community_store -->|"reads"| node_api_contracts
node_community_app -->|"authenticates"| node_firebase_client
node_electron_shell -->|"hosts"| node_app_shell
node_electron_shell -->|"enables"| node_player_runtime
node_electron_shell -->|"bridges"| node_app_services
node_community_app -->|"shares"| node_core_domain

click node_app_shell "https://github.com/ryohey/signal/blob/main/app/src/components/App/App.tsx"
click node_editor_views "https://github.com/ryohey/signal/blob/main/app/src/components/PianoRoll/PianoRoll.tsx"
click node_editor_canvas "https://github.com/ryohey/signal/blob/main/app/src/components/PianoRoll/PianoRollCanvas/PianoRollCanvas.tsx"
click node_gesture_handlers "https://github.com/ryohey/signal/blob/main/app/src/components/PianoRoll/MouseHandler/useNoteMouseGesture.ts"
click node_editor_state "https://github.com/ryohey/signal/blob/main/app/src/stores/RootStore.ts"
click node_app_services "https://github.com/ryohey/signal/blob/main/app/src/services/repositories.ts"
click node_player_runtime "https://github.com/ryohey/signal/blob/main/packages/player/src/Player.ts"
click node_core_domain "https://github.com/ryohey/signal/blob/main/packages/core/src/index.ts"
click node_core_song "https://github.com/ryohey/signal/blob/main/packages/core/src/entities/song/Song.ts"
click node_core_track "https://github.com/ryohey/signal/blob/main/packages/core/src/entities/track/Track.ts"
click node_core_commands "https://github.com/ryohey/signal/blob/main/packages/core/src/commands/CommandService.ts"
click node_core_midi "https://github.com/ryohey/signal/blob/main/packages/core/src/midi/midiConversion.ts"
click node_api_contracts "https://github.com/ryohey/signal/blob/main/packages/api/src/index.ts"
click node_cloud_functions "https://github.com/ryohey/signal/blob/main/functions/src/index.ts"
click node_firebase_client "https://github.com/ryohey/signal/blob/main/app/src/firebase/firebase.ts"
click node_community_app "https://github.com/ryohey/signal/blob/main/packages/community/src/index.tsx"
click node_community_store "https://github.com/ryohey/signal/blob/main/packages/community/src/stores/RootStore.ts"
click node_electron_shell "https://github.com/ryohey/signal/blob/main/electron/src/index.ts"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_app_shell,node_editor_views,node_editor_canvas,node_gesture_handlers,node_editor_state,node_app_services,node_player_runtime toneBlue
class node_core_domain,node_core_song,node_core_track,node_core_commands,node_core_midi toneAmber
class node_api_contracts,node_cloud_functions,node_firebase_client toneMint
class node_community_app,node_community_store toneRose
class node_electron_shell toneIndigo
```

## Components

### Editor app

React editor UI, stores, gestures, and canvas-backed sequencing views.

- [App shell](https://github.com/ryohey/signal/blob/main/app/src/components/App/App.tsx): react shell · Entry points, routing, auth, and global app composition. · `app/src/components/App/App.tsx`
- [Editor views](https://github.com/ryohey/signal/blob/main/app/src/components/PianoRoll/PianoRoll.tsx): editor panes · Piano roll, arrange, tempo, control, track list, and transport surfaces. · `app/src/components/PianoRoll/PianoRoll.tsx`
- [Canvas layers](https://github.com/ryohey/signal/blob/main/app/src/components/PianoRoll/PianoRollCanvas/PianoRollCanvas.tsx): gpu canvas · Timeline rendering layers for notes, grids, selections, and cursor overlays. · `app/src/components/PianoRoll/PianoRollCanvas/PianoRollCanvas.tsx`
- [Gestures](https://github.com/ryohey/signal/blob/main/app/src/components/PianoRoll/MouseHandler/useNoteMouseGesture.ts): pointer input · Drag, pencil, scroll, and selection interaction handlers across editor surfaces. · `app/src/components/PianoRoll/MouseHandler/useNoteMouseGesture.ts`
- [Editor state](https://github.com/ryohey/signal/blob/main/app/src/stores/RootStore.ts): stores/hooks · Central MobX-style stores and view hooks that coordinate editor state and commands. · `app/src/stores/RootStore.ts`
- [App services](https://github.com/ryohey/signal/blob/main/app/src/services/repositories.ts): persistence/io · Autosave, clipboard, MIDI I/O, IndexedDB storage, and repository adapters. · `app/src/services/repositories.ts`
- [Player runtime](https://github.com/ryohey/signal/blob/main/packages/player/src/Player.ts): audio scheduler · 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](https://github.com/ryohey/signal/blob/main/packages/core/src/index.ts): music model · Songs, tracks, selections, transforms, commands, and MIDI conversion. · `packages/core/src/index.ts`
- [Song model](https://github.com/ryohey/signal/blob/main/packages/core/src/entities/song/Song.ts): domain entity · Canonical song aggregate and factory logic for shared musical state. · `packages/core/src/entities/song/Song.ts`
- [Track model](https://github.com/ryohey/signal/blob/main/packages/core/src/entities/track/Track.ts): domain entity · Track events, validation, identification, and track-level transformations. · `packages/core/src/entities/track/Track.ts`
- [Commands](https://github.com/ryohey/signal/blob/main/packages/core/src/commands/CommandService.ts): domain services · Command services for arrange, control, conductor, and track mutations. · `packages/core/src/commands/CommandService.ts`
- [MIDI conversion](https://github.com/ryohey/signal/blob/main/packages/core/src/midi/midiConversion.ts): midi pipeline · 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](https://github.com/ryohey/signal/blob/main/packages/api/src/index.ts): repo interfaces · Repository interfaces for cloud songs, MIDI data, and users. · `packages/api/src/index.ts`
- [Cloud functions](https://github.com/ryohey/signal/blob/main/functions/src/index.ts): firebase backend · Server-side implementation for Firebase-backed application services. · `functions/src/index.ts`
- [Firebase client](https://github.com/ryohey/signal/blob/main/app/src/firebase/firebase.ts): auth/db 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](https://github.com/ryohey/signal/blob/main/packages/community/src/index.tsx): public react app · Browsing, profiles, sharing, and recent activity for public song discovery. · `packages/community/src/index.tsx`
- [Community state](https://github.com/ryohey/signal/blob/main/packages/community/src/stores/RootStore.ts): stores · 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](https://github.com/ryohey/signal/blob/main/electron/src/index.ts): desktop host · Main process, preload bridge, menus, IPC, and native system integration. · `electron/src/index.ts`

## Connections

- 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.
