Skip to the content.

Network Display Adapter

Beam now includes an optional browser adapter for projecting the current display state to tablets, phones, or any browser-capable device on the same network.

The current tablet client is optimized for distance reading. It renders the configured mood layout directly from displayItems, including %CoverArt, and keeps optional layered backgrounds made of a mood base layer plus an artist overlay.

Goals

Module Layout

The service is started and stopped from the main desktop frame. Configuration changes are applied through Beam settings, including the Preferences panel fields for enabling the service and setting the bind host and port.

Configuration

Additions to beamconfig.json:

"NetworkService": {
  "Enabled": "False",
  "Host": "0.0.0.0",
  "Port": 8765,
  "WebRoot": "resources/web/tablet"
}

Enabled defaults to False, so existing Beam installs continue to behave exactly as before.

The default network service port is 8765. You can keep that value or change it from Beam Preferences under Settings -> Network Display using the Port field.

HTTP API

GET /

Serves the tablet dashboard.

GET /media/background/current

Returns the currently selected Beam background image when one is available, otherwise returns 404 Not Found.

GET /media/background/base

Returns the current base background image used by the browser projection when one is available, otherwise returns 404 Not Found.

GET /media/cover-art/current

Returns the current track’s cover art image when the active layout includes %CoverArt and art is available, otherwise returns 404 Not Found.

GET /media/background/overlay

Returns the current overlay background image used by the browser projection when one is available, otherwise returns 404 Not Found.

GET /static/*

Serves the tablet client assets from resources/web/tablet.

GET /now-playing

Returns the latest serialized state document:

{
  "protocolVersion": 1,
  "schemaVersion": "2026-04-24",
  "sequence": 7,
  "snapshot": {
    "module": "Foobar2000",
    "playbackStatus": "Playing",
    "previousPlaybackStatus": "Paused",
    "statusMessage": "Playing",
    "moodName": "Default",
    "background": {
      "available": true,
      "sourcePath": "C:/.../background.jpg",
      "url": "/media/background/current",
      "base": {
        "available": true,
        "sourcePath": "C:/.../resources/backgrounds/curtain.jpg",
        "currentPath": "",
        "url": "/media/background/base",
        "reference": "asset:builtin/backgrounds/curtain.jpg",
        "canonicalReference": "asset:builtin/backgrounds/curtain.jpg",
        "relativePath": "backgrounds/curtain.jpg",
        "scope": "builtin",
        "kind": "asset",
        "rotate": "no",
        "rotateTimer": 120,
        "mode": "base",
        "opacity": 100,
        "name": "Default",
        "field": "",
        "matchedField": "",
        "operator": "",
        "value": ""
      },
      "overlay": {
        "available": true,
        "sourcePath": "C:/Users/.../.beam/backgrounds/orchestras/di-sarli.jpg",
        "currentPath": "",
        "url": "/media/background/overlay",
        "reference": "asset:user/backgrounds/orchestras/di-sarli.jpg",
        "canonicalReference": "asset:user/backgrounds/orchestras/di-sarli.jpg",
        "relativePath": "backgrounds/orchestras/di-sarli.jpg",
        "scope": "user",
        "kind": "asset",
        "rotate": "no",
        "rotateTimer": 120,
        "mode": "blend",
        "opacity": 40,
        "name": "Carlos Di Sarli",
        "field": "%AlbumArtist",
        "matchedField": "%AlbumArtist",
        "operator": "is",
        "value": "Carlos Di Sarli"
      }
    },
    "displayRows": ["..."],
    "displayItems": [
      {
        "index": 0,
        "text": "La Cumparsita",
        "field": "%Title",
        "active": "yes",
        "alignment": "Center",
        "font": "Georgia",
        "fontColor": "(255, 255, 255, 255)",
        "size": 10,
        "style": "Normal",
        "weight": "Bold",
        "position": [48, 50],
        "hideControl": "",
        "textFlow": "Cut"
      }
    ],
    "currentSong": {
      "title": "La Cumparsita",
      "artist": "Rodriguez",
      "album": "Golden Age",
      "genre": "Tango",
      "year": "1939-09-22",
      "albumArtist": "Rodriguez",
      "isCortina": "no",
      "filePath": "C:/Music/La Cumparsita.mp3",
      "ignoreSong": "no"
    },
    "previousSong": {
      "title": "El Once",
      "artist": "Di Sarli"
    },
    "nextSong": {
      "title": "Bahia Blanca",
      "artist": "Di Sarli"
    },
    "nextTandaSong": null,
    "playlist": [],
    "displayTimer": 0,
    "coverArt": {
      "available": true,
      "url": "/media/cover-art/current",
      "sourcePath": "C:/Music/La Cumparsita.mp3"
    },
    "coverArtAvailable": true
  }
}

Important notes:

WebSocket Protocol

GET /events

Upgrades to a WebSocket connection. Beam immediately sends a session.hello event with the current snapshot, then pushes state.updated events only when the serialized snapshot changes.

Initial event:

{
  "type": "session.hello",
  "protocolVersion": 1,
  "schemaVersion": "2026-04-24",
  "sequence": 7,
  "timestamp": "2026-04-24T20:41:00Z",
  "snapshot": {}
}

Update event:

{
  "type": "state.updated",
  "protocolVersion": 1,
  "schemaVersion": "2026-04-24",
  "sequence": 8,
  "timestamp": "2026-04-24T20:41:05Z",
  "snapshot": {}
}

Event Model

Tablet Client Behavior

Compatibility Notes

Migration Notes