Decentralized Browser-Native Music Player SDK Spec

Version: 1.0
Audience: Senior Engineers
Author: me
CO-Author: LLM - full conversation here


Overview

This SDK enables artists to self-host music players on their own websites with full control over content, monetization, and UI. It allows users to create personal, browser-stored playlists across multiple artist sites — without any central authority or cross-site tracking.

A shared iframe (on a neutral origin) acts as a client-side data store and playback engine, communicating with host pages via postMessage. All track storage, playlist assembly, and cross-tab coordination happen locally in the browser.


System Goals


Architecture Overview

... something like this

+----------------------------+       +--------------------------+
|   artist-a.com frontend    |       |   artist-b.net frontend  |
| - Loads sdk.js             |       | - Loads sdk.js           |
| - Calls sdk.sync(album)    |       | - Calls sdk.sync(album)  |
|                            |       |                          |
|        +---------------+   |       |   +---------------+      |
|        | player iframe |<------------->| player iframe |      |
|        | (player-hub)  |   Broadcast   +---------------+      |
|        +---------------+    Channel       ^     ^             |
|             ^      ^       |       |      |     |             |
+-------------|------|-------+       +------|-----|-------------+
              |      |                      |     | 
              |   +----------------------------+  |
              |   |   artist-a.com backend     |  |
              |   | - Serves authorized media  |  |
              |   +----------------------------+  |
              |                                   |
             +-------------------------------------+ 
             |      other-media-backend.io         |
             |      - Serves authorized media      |
             +-------------------------------------+

Components

1. sdk.js (Vanilla JS SDK, framework-agnostic)

SDK Public API:

playerSDK.init(options?: {
  headless?: boolean,
  allowOrigins?: string[], // e.g. ["artist-a.com"]
  ui?: "compact" | "full" | "none"
})

playerSDK.sync({
  collection: string,
  title?: string,
  cover?: string,
  origin?: string,
  tracks: TrackMetadata[]
})

playerSDK.on(event: string, callback: (payload) => void)

playerSDK.requestPlayback(trackId: string)

2. player.html (Shared iframe on https://player-hub.net/player.html)

Storage Schema:

type TrackMetadata = {
  id: string
  title: string
  url: string
  artist: string
  cover?: string
  duration?: number
  access?: {
    type: "free" | "subscription" | "purchase"
    allowedOrigins?: string[]
    auth?: {
      method: "token" | "header" | "cookie"
      endpoint: string
    }
  }
}

Security & Origin Validation


Message Protocol

Host → Iframe:

{ type: "sync", collection: string, tracks: TrackMetadata[], title?: string, cover?: string }
{ type: "play", trackId: string }
{ type: "pause" }
{ type: "requestPlaylist" }
{ type: "seek", seconds: number }

Iframe → Host:

{ type: "confirmationRequired", collection: string, tracks: TrackMetadata[] }
{ type: "syncComplete", collection: string, acceptedIds: string[] }
{ type: "playlistUpdated", playlist: TrackMetadata[] }
{ type: "playbackState", playing: boolean, trackId?: string }
{ type: "authRequired", trackId: string, reason: string }

Access Models & Auth Handling

Free Track:

Protected Track (purchase/subscription):


Confirmation & Permissions


Cross-Tab Communication

Uses BroadcastChannel('player-hub'):


External Backup / Sync Layer

The iframe supports registering an external sync adapter:

window.playerHub.registerSyncAdapter({
  name: "dropbox" | "solid" | "localExport",
  export(): Promise<BackupData>,
  import(data: BackupData): Promise<void>
})

Optional: Central Player Page

URL: https://player-hub.net/library


Future Considerations