vdo-streamdeck

Bitfocus Companion VDO.Ninja Module Research

Research date: 2026-06-30.

This summarizes the current Bitfocus Companion VDO.Ninja module so the native Stream Deck plugin can at least mirror it, then add Stream Deck specific controls and customization.

Sources Reviewed

Bryce / Companion History

Bryce Seifert is the author on the recent module releases and most recent feature work in the GitHub release history:

Release Relevant VDO.Ninja change
v1.1.0 Stops polling on module disable.
v2.2.0 Adds custom WebSocket server config.
v2.2.1 Improves feedback responsiveness and director presets.
v2.2.2 Allows stream variables on all streams, including rooms.
v2.3.0 Adds guest-in-scene feedback / variable.
v2.4.0 Upgrades to Node 22 and adds PTZ actions.
v2.5.0 Adds stream ID variables and variables in actions.

The native plugin should match the v2.5.0 surface as the parity baseline.

Runtime Architecture

The Companion module is intentionally lean:

Native plugin translation:

Companion State Handling

Incoming WebSocket messages are handled in two families:

Message form Companion behavior Native plugin implication
callback.action == "getDetails" Iterate result and call processGetDetails(data) for every stream. Use this as the full snapshot path.
callback.local Finds the local stream and updates it if the action was not a toggle. Native plugin should use callback result to update local button state quickly.
update Calls processUpdate(data). Use this as the incremental event path.

Important update actions:

Update action Companion behavior
hangup Deletes stream state and removes it from dropdown choices.
newViewConnection Requests fresh getDetails.
director Updates director state and rebuilds actions/variables/feedbacks.
endViewConnection Deletes stream by data.value.
positionChange Requests fresh getDetails.
directorMuted Stores director-enforced guest audio mute under others["mute-guest"].
directorVideoHide Stores director-enforced guest video hide under others["hide-guest"].
remoteMuted / mic Updates muted.
remoteVideoMuted / camera Updates videoMuted.
details Requests fresh getDetails.
seeding / tracksAdded Requests fresh getDetails.

Native plugin enhancement:

Companion Actions to Mirror

Local Actions

Companion action ID VDO.Ninja action
speaker speaker with toggle / true / false
mic mic with toggle / true / false
camera camera with toggle / true / false
volume volume percent
sendChat sendChat text
record record true / false
reload reload
hangup hangup
bitrate bitrate reset / pause / custom kbps
panning panning 0 to 180, center 90
togglehand togglehand
togglescreenshare togglescreenshare
forceKeyframe forceKeyframe
nextSlide nextSlide
previousSlide Companion action ID; current local VDO runtime confirms prevSlide as the actual VDO API action name
ptzPan local pan, value divided by 100
ptzTilt local tilt, value divided by 100
ptzZoom local zoom, value divided by 100
ptzFocus local focus, value divided by 100
ptzExposure local exposure, value divided by 100

Director / Room Actions

Companion action ID VDO.Ninja action
group self group
joinGroup self joinGroup
leaveGroup self leaveGroup
viewGroup self viewGroup
joinViewGroup self joinViewGroup
leaveViewGroup self leaveViewGroup
soloVideo soloVideo

Guest-Targeted Actions

Companion action ID VDO.Ninja action
guestForward forward
guestAddScene addScene
guestMuteScene muteScene
guestGroup group with target
guestMic mic with target
guestHangup hangup with target
guestSoloChat soloChat
guestAltSoloChat soloChatBidirectional
guestSpeaker speaker with target
guestDisplay display
guestOverlay sendDirectorChat
guestForceKeyframe forceKeyframe with target
guestSoloVideo soloVideo with target
guestVolume volume with target

Parity note: current Companion actions include local PTZ but not full guest PTZ actions in the action table despite v2.4.0 release notes. The VDO.Ninja API and local ptz.html support guest PTZ via ptzZoom, ptzPan, ptzTilt, ptzFocus, and ptzAutofocus; native Stream Deck should expose those directly.

Companion Feedbacks to Mirror

Feedback Inputs Logic
Mic status stream, muted/unmuted state Guest streams use others["mute-guest"] as director-enforced override; otherwise compare muted.
Camera status stream, muted/unmuted state Guest streams use others["hide-guest"] as director-enforced override; otherwise compare videoMuted.
Speaker status stream, muted/unmuted state Compare speakerMuted.
Guest in scene stream, scene ID/name Compare stream.scenes[scene] == true.

Native plugin should add:

Companion Variables and Presets

Variables:

Presets:

Native plugin should go further:

Native Stream Deck Enhancements Beyond Companion

Dials / Encoders

There are no physical faders/sliders in the Stream Deck family reviewed, but Stream Deck + and + XL have dials/encoders and an LCD touch strip/infobar. Use those for:

Better Customization

Better State Model

Mirror Companion’s states and streams, but add:

Red Flags Found