# prajasw/musi-type architecture

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

- Interactive diagram: https://gitdiagram.com/prajasw/musi-type
- Repository: https://github.com/prajasw/musi-type

## Overview

musi-type lets users choose a YouTube video, retrieve or supply lyrics, obtain usable line timings, then type along while the video is synchronized to their progress. The backend gathers metadata, captions, and lyric sources; it prefers synced lyrics, otherwise aligns plain lyrics to captions or optional Whisper audio timings. The React client handles playback, typing modes, scoring, settings, and results. The graph reflects README-documented capabilities as well as sampled imports and calls; some unsampled UI and backend details are represented only at subsystem level.

Main entry points: [`web/src/pages/Watch.tsx`](https://github.com/prajasw/musi-type/blob/main/web/src/pages/Watch.tsx) (Watch session), [`server/src/services/song.ts`](https://github.com/prajasw/musi-type/blob/main/server/src/services/song.ts) (Song resolution), [`server/src/services/audio.ts`](https://github.com/prajasw/musi-type/blob/main/server/src/services/audio.ts) (Audio transcription sync), [`server/src/routes/song.ts`](https://github.com/prajasw/musi-type/blob/main/server/src/routes/song.ts) (Song and sync routes)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_client["Web experience"]
  node_home["Song selection<br/>[Home.tsx]"]
  node_watch["Watch session<br/>[Watch.tsx]"]
  node_player["Video player"]
  node_typing["Typing session<br/>[useTyping.ts]"]
  node_typinglogic["Typing rules and scoring<br/>[typing.ts]"]
  node_typingui["Typing display<br/>[TypingArea.tsx]"]
  node_results["Session results<br/>[Results.tsx]"]
  node_keymap["On-screen keyboard<br/>[Keyboard.tsx]"]
  node_settings["Settings and themes<br/>[settings.tsx]"]
end

subgraph group_lyrics["Lyrics and timing"]
  node_song_service["Song resolution<br/>[song.ts]"]
  node_align["Lyric alignment<br/>[align.ts]"]
  node_captions["Caption parsing<br/>[captions.ts]"]
  node_audio["Audio transcription sync<br/>[audio.ts]"]
end

subgraph group_api["API and controls"]
  node_api_client["API client<br/>[api.ts]"]
  node_song_route["Song and sync routes<br/>[song.ts]"]
  node_app["HTTP application<br/>[app.ts]"]
  node_cache[("Song and audio cache<br/>[cache.ts]")]
end

subgraph group_sources["External sources"]
  node_youtube["YouTube video"]
  node_ytdlp["Video metadata and captions<br/>[ytdlp.ts]"]
  node_lrclib["LRCLIB lyrics<br/>[lrclib.ts]"]
  node_genius["Genius lyrics<br/>[genius.ts]"]
  node_whisper["Whisper transcription<br/>[transcribe.py]"]
  node_youtube_api["YouTube API / yt-dlp"]
end

node_user(("Listener / typist"))

node_user -->|"chooses video"| node_home
node_home -->|"requests song"| node_api_client
node_user -->|"types lyrics"| node_watch
node_watch -->|"fetches or aligns"| node_api_client
node_api_client -->|"calls API"| node_song_route
node_app -->|"routes requests"| node_song_route
node_song_route -->|"resolves lyrics"| node_song_service
node_song_route -->|"starts audio sync"| node_audio
node_song_service -->|"gets metadata and captions"| node_ytdlp
node_song_service -->|"fetches lyrics"| node_lrclib
node_song_service -->|"fetches fallback lyrics"| node_genius
node_song_service -->|"aligns lyric words"| node_align
node_song_service -->|"reads audio timings"| node_audio
node_song_service -->|"reads and writes"| node_cache
node_audio -->|"stores timings"| node_cache
node_ytdlp -->|"parses tracks"| node_captions
node_ytdlp -->|"gets video data"| node_youtube_api
node_audio -->|"downloads audio"| node_ytdlp
node_audio -->|"transcribes audio"| node_whisper
node_lrclib -.->|"none"| node_youtube_api
node_watch -->|"controls playback"| node_player
node_player -->|"plays video"| node_youtube
node_watch -->|"runs session"| node_typing
node_typing -->|"uses reducer and scoring"| node_typinglogic
node_watch -->|"renders lyrics"| node_typingui
node_watch -->|"renders keymap"| node_keymap
node_watch -->|"shows results"| node_results
node_typing -->|"provides session stats"| node_results
node_watch -->|"applies preferences"| node_settings
node_user -->|"sets typing options"| node_settings
node_watch -->|"holds or advances"| node_player

click node_home "https://github.com/prajasw/musi-type/blob/main/web/src/pages/Home.tsx"
click node_watch "https://github.com/prajasw/musi-type/blob/main/web/src/pages/Watch.tsx"
click node_player "https://github.com/prajasw/musi-type/blob/main/web/src/hooks/useYouTubePlayer.ts"
click node_typing "https://github.com/prajasw/musi-type/blob/main/web/src/hooks/useTyping.ts"
click node_typinglogic "https://github.com/prajasw/musi-type/blob/main/web/src/lib/typing.ts"
click node_typingui "https://github.com/prajasw/musi-type/blob/main/web/src/components/TypingArea.tsx"
click node_results "https://github.com/prajasw/musi-type/blob/main/web/src/components/Results.tsx"
click node_keymap "https://github.com/prajasw/musi-type/blob/main/web/src/components/Keyboard.tsx"
click node_settings "https://github.com/prajasw/musi-type/blob/main/web/src/lib/settings.tsx"
click node_api_client "https://github.com/prajasw/musi-type/blob/main/web/src/lib/api.ts"
click node_song_route "https://github.com/prajasw/musi-type/blob/main/server/src/routes/song.ts"
click node_app "https://github.com/prajasw/musi-type/blob/main/server/src/app.ts"
click node_song_service "https://github.com/prajasw/musi-type/blob/main/server/src/services/song.ts"
click node_align "https://github.com/prajasw/musi-type/blob/main/server/src/align/align.ts"
click node_captions "https://github.com/prajasw/musi-type/blob/main/server/src/services/captions.ts"
click node_audio "https://github.com/prajasw/musi-type/blob/main/server/src/services/audio.ts"
click node_cache "https://github.com/prajasw/musi-type/blob/main/server/src/cache.ts"
click node_ytdlp "https://github.com/prajasw/musi-type/blob/main/server/src/services/ytdlp.ts"
click node_lrclib "https://github.com/prajasw/musi-type/blob/main/server/src/services/lrclib.ts"
click node_genius "https://github.com/prajasw/musi-type/blob/main/server/src/services/genius.ts"
click node_whisper "https://github.com/prajasw/musi-type/blob/main/server/scripts/transcribe.py"

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_home,node_watch,node_player,node_typing,node_typinglogic,node_typingui,node_results,node_keymap,node_settings toneBlue
class node_song_service,node_align,node_captions,node_audio toneAmber
class node_api_client,node_song_route,node_app,node_cache toneMint
class node_youtube,node_ytdlp,node_lrclib,node_genius,node_whisper,node_youtube_api toneRose
class node_user toneIndigo
```

## Components

### Web experience

- [Song selection](https://github.com/prajasw/musi-type/blob/main/web/src/pages/Home.tsx): `web/src/pages/Home.tsx`
- [Watch session](https://github.com/prajasw/musi-type/blob/main/web/src/pages/Watch.tsx): `web/src/pages/Watch.tsx`
- [Video player](https://github.com/prajasw/musi-type/blob/main/web/src/hooks/useYouTubePlayer.ts): `web/src/hooks/useYouTubePlayer.ts`
- [Typing session](https://github.com/prajasw/musi-type/blob/main/web/src/hooks/useTyping.ts): `web/src/hooks/useTyping.ts`
- [Typing rules and scoring](https://github.com/prajasw/musi-type/blob/main/web/src/lib/typing.ts): `web/src/lib/typing.ts`
- [Typing display](https://github.com/prajasw/musi-type/blob/main/web/src/components/TypingArea.tsx): `web/src/components/TypingArea.tsx`
- [Session results](https://github.com/prajasw/musi-type/blob/main/web/src/components/Results.tsx): `web/src/components/Results.tsx`
- [On-screen keyboard](https://github.com/prajasw/musi-type/blob/main/web/src/components/Keyboard.tsx): `web/src/components/Keyboard.tsx`
- [Settings and themes](https://github.com/prajasw/musi-type/blob/main/web/src/lib/settings.tsx): `web/src/lib/settings.tsx`

### Lyrics and timing

- [Song resolution](https://github.com/prajasw/musi-type/blob/main/server/src/services/song.ts): `server/src/services/song.ts`
- [Lyric alignment](https://github.com/prajasw/musi-type/blob/main/server/src/align/align.ts): `server/src/align/align.ts`
- [Caption parsing](https://github.com/prajasw/musi-type/blob/main/server/src/services/captions.ts): `server/src/services/captions.ts`
- [Audio transcription sync](https://github.com/prajasw/musi-type/blob/main/server/src/services/audio.ts): `server/src/services/audio.ts`

### API and controls

- [API client](https://github.com/prajasw/musi-type/blob/main/web/src/lib/api.ts): `web/src/lib/api.ts`
- [Song and sync routes](https://github.com/prajasw/musi-type/blob/main/server/src/routes/song.ts): `server/src/routes/song.ts`
- [HTTP application](https://github.com/prajasw/musi-type/blob/main/server/src/app.ts): `server/src/app.ts`
- [Song and audio cache](https://github.com/prajasw/musi-type/blob/main/server/src/cache.ts): `server/src/cache.ts`

### External sources

- **YouTube video**
- [Video metadata and captions](https://github.com/prajasw/musi-type/blob/main/server/src/services/ytdlp.ts): `server/src/services/ytdlp.ts`
- [LRCLIB lyrics](https://github.com/prajasw/musi-type/blob/main/server/src/services/lrclib.ts): `server/src/services/lrclib.ts`
- [Genius lyrics](https://github.com/prajasw/musi-type/blob/main/server/src/services/genius.ts): `server/src/services/genius.ts`
- [Whisper transcription](https://github.com/prajasw/musi-type/blob/main/server/scripts/transcribe.py): `server/scripts/transcribe.py`
- **YouTube API / yt-dlp**

### Other components

- **Listener / typist**

## Connections

- Listener / typist → Song selection: chooses video
- Song selection → API client: requests song (evidence: `web/src/pages/Home.tsx`)
- Listener / typist → Watch session: types lyrics
- Watch session → API client: fetches or aligns (evidence: `web/src/pages/Watch.tsx`)
- API client → Song and sync routes: calls API
- HTTP application → Song and sync routes: routes requests (evidence: `server/src/app.ts`)
- Song and sync routes → Song resolution: resolves lyrics (evidence: `server/src/routes/song.ts`)
- Song and sync routes → Audio transcription sync: starts audio sync (evidence: `server/src/routes/song.ts`)
- Song resolution → Video metadata and captions: gets metadata and captions (evidence: `server/src/services/song.ts`)
- Song resolution → LRCLIB lyrics: fetches lyrics (evidence: `server/src/services/song.ts`)
- Song resolution → Genius lyrics: fetches fallback lyrics (evidence: `server/src/services/song.ts`)
- Song resolution → Lyric alignment: aligns lyric words (evidence: `server/src/services/song.ts`)
- Song resolution → Audio transcription sync: reads audio timings (evidence: `server/src/services/song.ts`)
- Song resolution → Song and audio cache: reads and writes (evidence: `server/src/services/song.ts`)
- Audio transcription sync → Song and audio cache: stores timings (evidence: `server/src/services/audio.ts`)
- Video metadata and captions → Caption parsing: parses tracks (evidence: `server/src/services/ytdlp.ts`)
- Video metadata and captions → YouTube API / yt-dlp: gets video data (evidence: `server/src/services/ytdlp.ts`)
- Audio transcription sync → Video metadata and captions: downloads audio (evidence: `server/src/services/audio.ts`)
- Audio transcription sync → Whisper transcription: transcribes audio
- LRCLIB lyrics → YouTube API / yt-dlp: none
- Watch session → Video player: controls playback (evidence: `web/src/pages/Watch.tsx`)
- Video player → YouTube video: plays video (evidence: `web/src/hooks/useYouTubePlayer.ts`)
- Watch session → Typing session: runs session (evidence: `web/src/pages/Watch.tsx`)
- Typing session → Typing rules and scoring: uses reducer and scoring (evidence: `web/src/hooks/useTyping.ts`)
- Watch session → Typing display: renders lyrics (evidence: `web/src/pages/Watch.tsx`)
- Watch session → On-screen keyboard: renders keymap (evidence: `web/src/pages/Watch.tsx`)
- Watch session → Session results: shows results (evidence: `web/src/pages/Watch.tsx`)
- Typing session → Session results: provides session stats (evidence: `web/src/components/Results.tsx`)
- Watch session → Settings and themes: applies preferences (evidence: `web/src/pages/Watch.tsx`)
- Listener / typist → Settings and themes: sets typing options
- Watch session → Video player: holds or advances (evidence: `web/src/pages/Watch.tsx`)
