Skip to content

WebSocket protocol

The presentation view (index.html) and speaker/notes view (notes.html) synchronise slide state over a real-time connection. The default transport is a WebSocket to the server at /ws. When running without a server (e.g. file:// or deployed), the system falls back to a BroadcastChannel named "slidesk_sync".

Both transports share the same message format.

Message format

All messages are JSON:

{
  "action": "<string>",
  "payload": <any>
}

payload is optional and type depends on the action.

Actions

Presentation → Speaker view

These messages originate from the presentation view when the slide changes:

Action Payload Description
"current" string Outer HTML of the current .sd-slide. The speaker view renders it in #sd-sv-current and extracts notes, timer data
"future" string Outer HTML of the next .sd-slide (empty string on last slide). Rendered in #sd-sv-future
"goto" number Current slide index. Used by the speaker view to look up timer checkpoints
"checkpoints" {timerCheckpoints, nbSlides} Timer checkpoint data sent once on page load

Speaker view → Presentation

The speaker view sends these actions on keyboard input:

Action Payload Description
"next" — Advance to next slide
"previous" — Go back to previous slide
"first" — Go to the first slide
"last" — Go to the last slide
"black" — Toggle the black screen

Any other function of window.slidesk in the presentation can be called the same way, which is how the keyboard plugin sends its actions.

Server → Client

The server sends these messages:

Action Payload Description
"reload" — Trigger a full page reload (sent when files change)

CLI → Server → Client

When interacting via the command line (slidesk present --goto 5, slidesk present --next, etc.):

Action Data Description
"goto" number Jump to a slide
"next" — Next slide
"previous" — Previous slide

The CLI sends these through server.send(action, data), which publishes {"action": <action>, "data": <data>} to the "slidesk" channel. The client handles them via window.slidesk[data.action](data).

Dynamic method dispatch

When the client receives an action it does not recognise, it falls through to:

window.slidesk[data.action](data);

This allows any method on window.slidesk (e.g. fullscreen, next, previous, goto) to be called remotely by setting the action to the method name. Only functions defined directly on window.slidesk, by SliDesk or a plugin, are called: other names are ignored.

Reconnection

When slidesk present is restarted, the pages that were connected retry the websocket (from 0.5 s up to every 5 s) and reload once it is back, so they show the new build. A page that never connected, such as a static export, does not retry.

Plugin WebSocket messages

When a plugin defines an addWS handler in its plugin.json, the server routes messages that include a plugin field:

{
  "plugin": "<plugin_name>",
  "message": "..."
}

The server calls the plugin's WebSocket handler with the raw JSON string and broadcasts the response as:

{
  "action": "<plugin_name>_response",
  "response": <handler_return_value>
}

All clients subscribed to "slidesk" receive the response.

Unrecognised messages

Any message that does not match the built-in actions is broadcast as-is to all clients on the "slidesk" channel. On the receiving end, if window.slidesk[data.action] is a function defined on window.slidesk, it is called with data as the argument.

Example flow: slide change

sequenceDiagram
    participant P as Presentation
    participant W as WebSocket
    participant S as Speaker view

    P->>P: changeSlide()
    P->>W: current + slide outerHTML
    W->>S: current + slide outerHTML
    S->>S: render & extract notes & timers
    P->>W: future + next slide outerHTML
    W->>S: future + next slide outerHTML
    S->>S: render future slide
    P->>W: goto + slide number
    W->>S: goto + slide number
    S->>S: update checkpoints

    S->>W: previous
    W->>P: previous
    P->>P: previous() on ArrowLeft

    S->>W: next
    W->>P: next
    P->>P: next() on ArrowRight

BroadcastChannel fallback

When window.location.origin is "file://" or the WebSocket connection fails, the client creates a BroadcastChannel("slidesk_sync"). The message format is identical. This enables synchronisation between the presentation and speaker view when both are opened locally from the file system or from a deployed static site.