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.