Skip to content

Technical architecture ​

Overview ​

Tech stack ​

ComponentTechnologyRole
Desktop frameworkTauri 2.x (Rust)Native window, IPC, packaging
InterfaceVue.js 3 + Composition APIReactive UI
State managementPiniaGlobal state
Internationalisationvue-i18nFR / EN / ES / JA
CommunicationWebSocket (tokio-tungstenite)OBS overlay + Stream Deck
Unit testsVitestComposables, stores
E2E testsPlaywrightFull flows

The four components ​

1. Main application (Tauri) ​

The heart of the system. The user manages their setlist, configures decks and controls playback here. Any change triggers a WebSocket broadcast to all connected clients.

Built with Vue.js 3 on the UI side and Rust on the backend. Tauri bridges the two via typed IPC commands.

2. OBS Overlay ​

A simple HTML file (obs-overlay/index.html) added as a Browser Source in OBS Studio. It connects to the app's WebSocket and updates the display on each PLAYING_UPDATE message. No external server required — everything goes through localhost.

3. Stream Deck Plugin ​

A JavaScript plugin for Elgato Stream Deck. Each button represents a deck. It connects to the same WebSocket and sends commands back (TOGGLE_DECK, PLAY_TRACK, STOP_DECK). Buttons update dynamically (artwork, title, playing/idle state).

4. dlp-player npm widget ​

A standalone JavaScript package (npm publication pending). It reads a playlist JSON exported from DLP and synchronises track display with a media player (<video>, <audio>, YouTube or SoundCloud iframe). Two display modes: list (tracklist beside the player) and overlay (superimposed at the bottom). Zero dependency on the desktop app — works entirely client-side.

The WebSocket server ​

The Rust backend starts a WebSocket server on localhost:9876 when the app launches. It handles:

  • Multiple connections — OBS Overlay + Stream Deck can be connected simultaneously
  • Broadcast — when a track changes, all clients receive PLAYING_UPDATE
  • Config sync — the Stream Deck plugin sends GET_DECKS_CONFIG on startup to retrieve the configured decks

Protocol ​

Any WebSocket client can connect — no authentication, the server is local only.

javascript
const ws = new WebSocket('ws://localhost:9876')

ws.onmessage = (event) => {
  const { type, payload } = JSON.parse(event.data)
  if (type === 'PLAYING_UPDATE') {
    // Update the display
  }
}

Outgoing messages (App → Clients) ​

PLAYING_UPDATE — Sent when the currently playing tracks change.

json
{
  "type": "PLAYING_UPDATE",
  "payload": {
    "tracks": [
      {
        "id": "uuid",
        "title": "Track Title",
        "artist": "Artist Name",
        "image": "data:image/jpeg;base64,... or URL",
        "deckName": "Vinyl 1",
        "qrCodeUrl": "https://..."
      }
    ]
  }
}

DECK_CANDIDATES — Response to GET_DECK_CANDIDATES. Provides available tracks for a given deck.

json
{
  "type": "DECK_CANDIDATES",
  "payload": {
    "deckId": "deck-1",
    "currentlyPlaying": { "id": "...", "title": "...", "artist": "...", "image": "..." },
    "lastPlayed":       { "id": "...", "title": "...", "artist": "...", "image": "..." },
    "nextUnplayed":     { "id": "...", "title": "...", "artist": "...", "image": "..." }
  }
}

DECKS_CONFIG — Response to GET_DECKS_CONFIG. Lists all configured decks.

json
{
  "type": "DECKS_CONFIG",
  "payload": {
    "decks": [
      { "id": "deck-1", "name": "Vinyl 1", "deckType": "vinyl", "image": "data:image/png;base64,..." },
      { "id": "deck-2", "name": "CDJ 1",   "deckType": "cd",    "image": "data:image/png;base64,..." }
    ]
  }
}

CONFIG_UPDATE — Sent when the overlay visual configuration changes (theme, display options, animations).

Incoming messages (Clients → App) ​

MessagePayloadDescription
GET_DECKS_CONFIG{}Request the list of configured decks
TOGGLE_DECK{ "deck_id": "deck-1" }Toggle a deck on/off
GET_DECK_CANDIDATES{ "deck_id": "deck-1" }Request candidate tracks for a deck
PLAY_TRACK{ "track_id": "uuid" }Start playing a specific track
STOP_DECK{ "deck_id": "deck-1" }Stop a deck

Deck types ​

ValueDescription
vinylVinyl turntable
cdCD player / CDJ
controllerDJ controller
softwareSoftware (Rekordbox, Serato, Traktor...)

Version management ​

The version is defined once in package.json and automatically synced to tauri.conf.json and Cargo.toml via a sync-version.js script, called automatically before each build and tauri via npm prebuild / pretauri hooks.