WebSocket API Code Example
// Connect to WebSocket API const socket = new WebSocket("wss://api.vdo.ninja:443"); // Track connection state socket.onopen = function() { console.log("Connected to VDO.Ninja API"); // Join with your API ID socket.send(JSON.stringify({ "join": "YOUR_API_ID" })); }; // Handle messages socket.onmessage = function(event) { if (event.data) { const data = JSON.parse(event.data); console.log("Received:", data); } }; // Reconnection logic (crucial for production) socket.onclose = function() { console.log("Connection closed, attempting to reconnect..."); setTimeout(() => { // Implement reconnection logic here }, 1000); }; // Example commands function sendCommand(action, value = null, value2 = null, target = null) { const msg = { action }; if (value !== null) msg.value = value; if (value2 !== null) msg.value2 = value2; if (target !== null) msg.target = target; if (socket.readyState === WebSocket.OPEN) { socket.send(JSON.stringify(msg)); } else { console.error("Socket not connected"); } } // Command examples: // sendCommand("mic", "toggle"); // sendCommand("camera", false); // sendCommand("soloVideo", "toggle"); // sendCommand("layout", 2); // Camera control examples: // sendCommand("zoom", 0.1); // Relative zoom in 10% // sendCommand("zoom", 0.75, "abs"); // Absolute zoom to 75% // sendCommand("pan", -0.1); // Relative pan left 10% // sendCommand("focus", 0.1); // Relative focus far 10% // sendCommand("focus", 0.5, "abs"); // Absolute focus to 50% // For directors - target a guest: // sendCommand("mic", "toggle", null, "1"); // Toggle guest 1's mic // sendCommand("zoom", 0.1, null, "2"); // Zoom guest 2's camera in
https://api.vdo.ninja/YOUR_API_ID/action/target/value
HTTP API Code Example
// HTTP GET API Example function sendHTTPRequest(apiID, action, target = "null", value = "null") { // Construct URL const url = `https://api.vdo.ninja/${apiID}/${action}/${target}/${value}`; // Send request fetch(url) .then(response => { if (!response.ok) { throw new Error(`HTTP error! Status: ${response.status}`); } return response.text(); }) .then(data => { // Handle response (could be text or JSON) try { const jsonData = JSON.parse(data); console.log("Response JSON:", jsonData); } catch (e) { console.log("Response text:", data); } }) .catch(error => { console.error("Error:", error); }); } // Usage examples: // sendHTTPRequest("YOUR_API_ID", "mic", "null", "toggle"); // sendHTTPRequest("YOUR_API_ID", "camera", "null", "false"); // sendHTTPRequest("YOUR_API_ID", "joinGroup", "null", "1"); // Camera control examples (relative adjustments only via HTTP): // sendHTTPRequest("YOUR_API_ID", "zoom", "null", "0.1"); // Zoom in 10% // sendHTTPRequest("YOUR_API_ID", "zoom", "null", "-0.1"); // Zoom out 10% // sendHTTPRequest("YOUR_API_ID", "pan", "null", "-0.1"); // Pan left 10% // sendHTTPRequest("YOUR_API_ID", "focus", "null", "0.1"); // Focus far 10% // For directors targeting a specific guest // sendHTTPRequest("YOUR_API_ID", "mic", "1", "toggle"); // Target guest in slot 1 // sendHTTPRequest("YOUR_API_ID", "zoom", "2", "0.1"); // Zoom guest 2's camera in
SSE provides a one-way communication channel to receive events from VDO.Ninja without sending requests.
SSE API Code Example
// Server-Sent Events (SSE) Example function connectToSSE(apiID) { // Create EventSource connection const eventSource = new EventSource(`https://api.vdo.ninja/sse/${apiID}`); // Connection opened eventSource.onopen = function() { console.log("SSE connection established"); }; // Listen for messages eventSource.onmessage = function(event) { try { const data = JSON.parse(event.data); console.log("SSE event:", data); // Handle different types of events if (data.type === "state_update") { // Handle state updates updateUI(data.state); } else if (data.type === "guest_joined") { // Handle guest joining console.log(`Guest joined: ${data.guestID}`); } // Add more event handlers as needed } catch (e) { console.error("Error parsing SSE event:", e); } }; // Handle errors eventSource.onerror = function(error) { console.error("SSE connection error:", error); // Close connection eventSource.close(); // Implement reconnection logic setTimeout(() => { console.log("Attempting to reconnect SSE..."); connectToSSE(apiID); }, 3000); }; // Return EventSource instance (for later disconnection if needed) return eventSource; } // Usage: // const sseConnection = connectToSSE("YOUR_API_ID"); // // // To disconnect later: // // sseConnection.close();
The HTTP POST method supports all features including the value2 parameter for absolute camera positioning.
HTTP POST API Code Example
// HTTP POST API Example function sendPOSTRequest(apiID, data) { // Construct URL const url = `https://api.vdo.ninja/${apiID}`; // Configure request const options = { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data) }; // Send request fetch(url, options) .then(response => { if (!response.ok) { throw new Error(`HTTP error! Status: ${response.status}`); } return response.json(); }) .then(data => { console.log("Response:", data); }) .catch(error => { console.error("Error:", error); }); } // Usage examples: // sendPOSTRequest("YOUR_API_ID", { // action: "mic", // value: "toggle" // }); // // Camera control with absolute positioning: // sendPOSTRequest("YOUR_API_ID", { // action: "zoom", // value: 0.75, // value2: "abs" // Sets zoom to exactly 75% // }); // // Camera control with relative adjustments: // sendPOSTRequest("YOUR_API_ID", { // action: "pan", // value: -0.1 // Pan left by 10% // }); // // sendPOSTRequest("YOUR_API_ID", { // action: "layout", // value: [ // {"x":0,"y":0,"w":50,"h":100,"slot":0}, // {"x":50,"y":0,"w":50,"h":100,"slot":1} // ] // }); // // For directors targeting a specific guest: // sendPOSTRequest("YOUR_API_ID", { // action: "zoom", // target: "2", // value: 0.1 // Zoom in guest 2's camera by 10% // });
Remote control compatible camera hardware using pan, tilt, zoom, focus, and exposure commands. Supports both relative and absolute positioning.
Zoom
Focus
Pan & Tilt
Exposure
Camera Presets
PTZ Controls Code Example
// Camera Control (PTZ) Example function sendCameraCommand(apiID, action, value, value2 = null, target = null) { // Using WebSocket (preferred for responsive camera control) if (socket && socket.readyState === WebSocket.OPEN) { const command = { action, value }; if (value2 !== null) command.value2 = value2; if (target !== null) command.target = target; socket.send(JSON.stringify(command)); } // Using HTTP POST (supports all features including value2) else { const url = `https://api.vdo.ninja/${apiID}`; const data = { action, value }; if (value2 !== null) data.value2 = value2; if (target !== null) data.target = target; fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data) }) .then(response => response.json()) .then(data => console.log("Response:", data)) .catch(error => console.error("Error:", error)); } } // RELATIVE ADJUSTMENTS (change from current position) // sendCameraCommand("YOUR_API_ID", "zoom", 0.1); // Zoom in by 10% // sendCameraCommand("YOUR_API_ID", "zoom", -0.1); // Zoom out by 10% // sendCameraCommand("YOUR_API_ID", "focus", 0.1); // Focus farther by 10% // sendCameraCommand("YOUR_API_ID", "focus", -0.1); // Focus nearer by 10% // sendCameraCommand("YOUR_API_ID", "pan", -0.1); // Pan left by 10% // sendCameraCommand("YOUR_API_ID", "pan", 0.1); // Pan right by 10% // sendCameraCommand("YOUR_API_ID", "tilt", 0.1); // Tilt up by 10% // sendCameraCommand("YOUR_API_ID", "tilt", -0.1); // Tilt down by 10% // sendCameraCommand("YOUR_API_ID", "exposure", 0.1); // Increase exposure by 10% // sendCameraCommand("YOUR_API_ID", "exposure", -0.1); // Decrease exposure by 10% // ABSOLUTE POSITIONING (set to exact values) // sendCameraCommand("YOUR_API_ID", "zoom", 1.5, "abs"); // Set zoom to 1.5x // sendCameraCommand("YOUR_API_ID", "focus", 0.75, "abs"); // Set focus to 75% // sendCameraCommand("YOUR_API_ID", "pan", 0, "abs"); // Center pan // sendCameraCommand("YOUR_API_ID", "pan", -0.5, "abs"); // Pan 50% left // sendCameraCommand("YOUR_API_ID", "tilt", 0.25, "abs"); // Tilt 25% up // sendCameraCommand("YOUR_API_ID", "exposure", 0.8, "abs"); // Set exposure to 80% // Camera presets using absolute positioning function setCameraPreset(preset) { switch(preset) { case 1: // Center position sendCameraCommand("YOUR_API_ID", "zoom", 1.0, "abs"); sendCameraCommand("YOUR_API_ID", "pan", 0, "abs"); sendCameraCommand("YOUR_API_ID", "tilt", 0, "abs"); break; case 2: // Wide shot sendCameraCommand("YOUR_API_ID", "zoom", 0.5, "abs"); sendCameraCommand("YOUR_API_ID", "pan", 0, "abs"); sendCameraCommand("YOUR_API_ID", "tilt", 0, "abs"); break; case 3: // Close-up sendCameraCommand("YOUR_API_ID", "zoom", 2.0, "abs"); sendCameraCommand("YOUR_API_ID", "pan", 0, "abs"); sendCameraCommand("YOUR_API_ID", "tilt", 0, "abs"); break; } } // Targeting a specific guest's camera (for directors) // sendCameraCommand("YOUR_API_ID", "zoom", 0.1, null, "2"); // Zoom guest 2's camera in // sendCameraCommand("YOUR_API_ID", "pan", -0.5, "abs", "1"); // Set guest 1's pan to 50% left
Control VDO.Ninja using MIDI controllers with various mapping options.
No MIDI message received
Default MIDI Mappings
VDO.Ninja supports several MIDI mapping schemes, which can be configured using the &midiHotkeys
parameter.
- G3: Toggle chat
- A3: Toggle mic
- B3: Toggle video
- C4: Toggle screenshare
- D4: Hangup
- E4: Raise hand
- F4: Toggle recording
- G4: Director audio
- A4: Director hangup
- B4: Toggle speaker
- G1: Toggle chat
- A1: Toggle mic
- B1: Toggle video
- C2: Toggle screenshare
- D2: Hangup
- E2: Raise hand
- F2: Toggle recording
- G2: Director audio
- A2: Director hangup
- B2: Toggle speaker
Uses note C1 with different velocity values:
- C1 + velocity 0: Toggle chat
- C1 + velocity 1: Toggle mic
- C1 + velocity 2: Toggle video
- C1 + velocity 3: Toggle screenshare
- C1 + velocity 4: Hangup
- C1 + velocity 5: Raise hand
- C1 + velocity 6: Toggle recording
- C1 + velocity 7: Director audio
- C1 + velocity 8: Director hangup
- C1 + velocity 9: Toggle speaker
CC 110 Commands:
- Value 20: Zoom in (+10%)
- Value 21: Zoom out (-10%)
- Value 22: Pan left (-10%)
- Value 23: Pan right (+10%)
- Value 24: Tilt up (+10%)
- Value 25: Tilt down (-10%)
- Value 26: Exposure up (+10%)
- Value 27: Exposure down (-10%)
- Value 28: Focus near (-10%)
- Value 29: Focus far (+10%)
- Value 30-32: Camera presets 1-3
CC 80-84 (Absolute Control):
- CC80: Zoom (0-127 → 0-2x)
- CC81: Pan (0-127 → -1 to +1)
- CC82: Tilt (0-127 → -1 to +1)
- CC83: Exposure (0-127 → 0-1)
- CC84: Focus (0-127 → 0-1)
MIDI API Code Example
// MIDI Integration Example function initializeMIDI() { // Check if Web MIDI API is supported if (!navigator.requestMIDIAccess) { console.error("Web MIDI API not supported in this browser"); return Promise.reject("MIDI not supported"); } // Request MIDI access return navigator.requestMIDIAccess({ sysex: false }) .then(midiAccess => { console.log("MIDI Access granted"); // Get MIDI inputs const inputs = midiAccess.inputs.values(); const devices = []; // Setup devices for (let input = inputs.next(); input && !input.done; input = inputs.next()) { devices.push(input.value); setupMIDIDevice(input.value); } // Listen for device connection/disconnection midiAccess.onstatechange = function(e) { console.log("MIDI state change:", e.port.name, e.port.state); }; return { midiAccess, devices }; }) .catch(error => { console.error("Failed to get MIDI access:", error); throw error; }); } function setupMIDIDevice(inputDevice) { // Set up MIDI message handler inputDevice.onmidimessage = function(message) { // Extract MIDI data const command = message.data[0]; const note = message.data[1]; const velocity = message.data[2]; console.log(`MIDI message - Command: ${command}, Note: ${note}, Velocity: ${velocity}`); // Handle Note On messages (144 = Note On, channel 1) if (command === 144 && velocity > 0) { handleNoteOn(note, velocity); } // Handle Note Off messages (128 = Note Off, channel 1) else if (command === 128 || (command === 144 && velocity === 0)) { handleNoteOff(note); } // Handle Control Change messages (176 = CC, channel 1) else if (command === 176) { handleControlChange(note, velocity); } }; } function handleControlChange(cc, value) { // Map control change messages to actions // CC110 - Advanced commands if (cc === 110) { switch(value) { case 20: sendCommand("zoom", 0.1); break; // Zoom in case 21: sendCommand("zoom", -0.1); break; // Zoom out case 22: sendCommand("pan", -0.1); break; // Pan left case 23: sendCommand("pan", 0.1); break; // Pan right case 24: sendCommand("tilt", 0.1); break; // Tilt up case 25: sendCommand("tilt", -0.1); break; // Tilt down case 26: sendCommand("exposure", 0.1); break; // Exposure up case 27: sendCommand("exposure", -0.1); break; // Exposure down case 28: sendCommand("focus", -0.1); break; // Focus near case 29: sendCommand("focus", 0.1); break; // Focus far case 30: // Camera preset 1 sendCommand("zoom", 1.0, "abs"); sendCommand("pan", 0, "abs"); sendCommand("tilt", 0, "abs"); break; // Add more CC110 values as needed } } // CC80-84: Absolute camera controls else if (cc >= 80 && cc <= 84) { const normalizedValue = value / 127; // 0-1 range switch(cc) { case 80: // Zoom absolute (0-127 maps to 0-2x zoom) sendCommand("zoom", normalizedValue * 2, "abs"); break; case 81: // Pan absolute (0-127 maps to -1 to +1) sendCommand("pan", (normalizedValue * 2) - 1, "abs"); break; case 82: // Tilt absolute (0-127 maps to -1 to +1) sendCommand("tilt", (normalizedValue * 2) - 1, "abs"); break; case 83: // Exposure absolute (0-127 maps to 0-1) sendCommand("exposure", normalizedValue, "abs"); break; case 84: // Focus absolute (0-127 maps to 0-1) sendCommand("focus", normalizedValue, "abs"); break; } } } // Helper function to convert MIDI note number to note name function getNoteNameFromNumber(noteNumber) { const notes = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"]; const octave = Math.floor(noteNumber / 12) - 1; const noteName = notes[noteNumber % 12]; return noteName + octave; } // Usage: // initializeMIDI() // .then(midi => console.log("MIDI ready with devices:", midi.devices)) // .catch(error => console.error("MIDI setup failed:", error));
These controls allow directors to manage remote guests via the API.
Guest Control Code Example
// Guest Control Example (Director Mode) function controlGuest(apiID, target, action, value = null, value2 = null, method = "websocket") { if (method === "websocket") { // WebSocket method (supports all features including value2) if (socket && socket.readyState === WebSocket.OPEN) { const msg = { target: target, action: action }; if (value !== null) msg.value = value; if (value2 !== null) msg.value2 = value2; socket.send(JSON.stringify(msg)); console.log("Sent guest command via WebSocket:", msg); } else { console.error("WebSocket not connected"); } } else if (method === "http") { // HTTP method (limited - no value2 support) const targetStr = target || "null"; const valueStr = value !== null ? value : "null"; const url = `https://api.vdo.ninja/${apiID}/${action}/${targetStr}/${valueStr}`; fetch(url) .then(response => response.text()) .then(data => console.log("Guest command response:", data)) .catch(error => console.error("Error sending guest command:", error)); } } // Basic guest control examples: // controlGuest("YOUR_API_ID", "1", "mic", "toggle"); // Toggle mic for guest 1 // controlGuest("YOUR_API_ID", "2", "camera", false); // Turn off camera for guest 2 // controlGuest("YOUR_API_ID", "3", "addScene", 1); // Add guest 3 to scene 1 // controlGuest("YOUR_API_ID", "1", "sendDirectorChat", "You're live in 10 seconds"); // controlGuest("YOUR_API_ID", "2", "volume", 85); // Set guest 2 volume to 85% // controlGuest("YOUR_API_ID", "4", "forward", "room123"); // Transfer guest 4 to room123 // Camera control for specific guests: // Relative adjustments // controlGuest("YOUR_API_ID", "1", "zoom", 0.1); // Zoom guest 1's camera in by 10% // controlGuest("YOUR_API_ID", "2", "pan", -0.1); // Pan guest 2's camera left by 10% // controlGuest("YOUR_API_ID", "3", "focus", 0.1); // Focus guest 3's camera farther // Absolute positioning (WebSocket only) // controlGuest("YOUR_API_ID", "1", "zoom", 1.5, "abs"); // Set guest 1's zoom to 1.5x // controlGuest("YOUR_API_ID", "2", "pan", 0, "abs"); // Center guest 2's pan // controlGuest("YOUR_API_ID", "3", "tilt", -0.25, "abs"); // Tilt guest 3's camera 25% down // controlGuest("YOUR_API_ID", "4", "exposure", 0.8, "abs"); // Set guest 4's exposure to 80%
Complete reference for all supported API commands, parameters, and response formats.
API Overview
The VDO.Ninja API supports multiple communication methods:
- WebSocket API: Real-time bidirectional communication (preferred for most uses)
- HTTP GET API: Simple REST-style requests, compatible with hotkey systems
- HTTP POST API: For complex data structures like layout objects and supports value2 parameter
- Server-Sent Events (SSE): One-way communication channel for receiving updates
- MIDI Integration: Control via MIDI devices using various mapping schemes
For integrations with BitFocus Companion, check out the official Companion module.
For custom embeds, refer to the IFrame API Documentation.
Command Reference
The following tables list all available commands, their parameters, and what they do.
Self Controls
Action | Target | Value | Details |
---|---|---|---|
speaker | null | true/false/toggle | Control local speaker (audio playback) |
mic | null | true/false/toggle | Control local microphone |
camera | null | true/false/toggle | Control local camera (same as video) |
video | null | true/false/toggle | Control local camera (alternate command) |
volume | null | true/false/0-100 | Control playback volume of all audio tracks (true=100%, false=0%) |
record | null | true/false | Start/stop recording the local video stream |
bitrate | null | true/false/integer | Control video bitrate (true=reset, false=pause, integer=kbps) |
panning | null | true/false/0-180 | Control stereo panning (90=center) |
reload | null | null | Reload the current page |
hangup | null | null | Disconnect current session |
togglehand | null | null | Toggle raised hand status |
togglescreenshare | null | null | Toggle screen sharing |
forceKeyframe | null | null | Force keyframe ("rainbow puke fix") |
sendChat | null | string | Send chat message to all connected users |
getDetails | null | null | Get detailed state information |
soloVideo | null | true/false/toggle | Highlight video for all guests (director only) |
Layout Controls
Action | Value | Details |
---|---|---|
layout | integer/object/array | Switch to layout by index (0=auto-mix, 1-8=custom layouts) or set custom layout with object |
Group Controls
Action | Value | Details |
---|---|---|
group | 1-8 | Toggle in/out of specified group |
joinGroup | 1-8 | Join specified group |
leaveGroup | 1-8 | Leave specified group |
viewGroup | 1-8 | Toggle preview of specified group |
joinViewGroup | 1-8 | Preview specified group |
leaveViewGroup | 1-8 | Stop previewing specified group |
Camera Control (PTZ)
Action | Value | Value2 | Details |
---|---|---|---|
zoom | decimal (-1 to 1 relative, 0-2 absolute) | "abs" or "true" (optional) | Adjust zoom. Relative: positive=in, negative=out. Absolute: 0-2x zoom when value2="abs" |
focus | decimal (-1 to 1 relative, 0-1 absolute) | "abs" or "true" (optional) | Adjust focus. Relative: positive=far, negative=near. Absolute: 0-1 range when value2="abs" |
pan | decimal (-1 to 1) | n/a | Adjust pan (always absolute). -1=full left, 0=center, 1=full right |
tilt | decimal (-1 to 1 relative or absolute) | "abs" or "true" (optional) | Adjust tilt. Relative: positive=up, negative=down. Absolute: -1 to 1 range when value2="abs" |
exposure | decimal (-1 to 1 relative, 0-1 absolute) | "abs" or "true" (optional) | Adjust exposure. Relative: positive=brighter, negative=darker. Absolute: 0-1 range when value2="abs" |
Guest Controls (Director Mode)
Action | Target | Value | Value2 | Details |
---|---|---|---|---|
forward | guest slot/ID | room name | n/a | Transfer guest to specified room |
addScene | guest slot/ID | 0-8 or scene name | n/a | Toggle guest in/out of specified scene |
muteScene | guest slot/ID | scene (optional) | n/a | Toggle guest's mic in scenes |
mic | guest slot/ID | true/false/toggle | n/a | Control guest's microphone |
camera | guest slot/ID | true/false/toggle | n/a | Control guest's camera |
video | guest slot/ID | true/false/toggle | n/a | Control guest's camera (alternate command) |
hangup | guest slot/ID | null | n/a | Disconnect guest |
soloChat | guest slot/ID | null | n/a | Toggle one-way solo chat with guest |
soloChatBidirectional | guest slot/ID | null | n/a | Toggle two-way solo chat with guest |
speaker | guest slot/ID | null | n/a | Toggle guest's speaker |
display | guest slot/ID | null | n/a | Toggle guest's display (ability to see video) |
group | guest slot/ID | 1-8 | n/a | Toggle guest in/out of specified group |
forceKeyframe | guest slot/ID | null | n/a | Trigger keyframe for guest (fix rainbow artifacts) |
soloVideo | guest slot/ID | null | n/a | Toggle highlighting guest's video |
sendChat | guest slot/ID | message text | n/a | Send private chat message to guest |
sendDirectorChat | guest slot/ID | message text | n/a | Send message and overlay it on guest's screen |
volume | guest slot/ID | 0-200 | n/a | Set guest's microphone volume |
startRoomTimer | guest slot/ID | seconds | n/a | Start countdown timer for guest |
pauseRoomTimer | guest slot/ID | null | n/a | Pause timer for guest |
stopRoomTimer | guest slot/ID | null | n/a | Stop timer for guest |
mixorder | guest slot/ID | -1 or 1 | n/a | Adjust guest's position in the mixer (-1=up, 1=down) |
zoom | guest slot/ID | decimal (see Camera Control) | "abs" or "true" (optional) | Control guest's camera zoom |
focus | guest slot/ID | decimal (see Camera Control) | "abs" or "true" (optional) | Control guest's camera focus |
pan | guest slot/ID | decimal -1 to 1 | n/a | Control guest's camera pan (absolute only) |
tilt | guest slot/ID | decimal (see Camera Control) | "abs" or "true" (optional) | Control guest's camera tilt |
exposure | guest slot/ID | decimal (see Camera Control) | "abs" or "true" (optional) | Control guest's camera exposure |
Response Formats
Responses from the API depend on the method used:
- HTTP GET: Responses include simple text values like
true
,false
,null
,fail
, or a specific value. For object responses likegetDetails
, you'll receive JSON. - WebSocket: Responses are JSON objects containing the result along with the original request parameters and any custom data fields you included.
- HTTP POST: Responses are JSON objects with similar structure to WebSocket responses.
- SSE: Events are JSON objects containing state updates and other notifications.
Camera Control Details
The camera control commands support both relative and absolute positioning:
- Relative adjustments: Changes are applied from the current position. Use decimal values like 0.1 for +10% or -0.1 for -10%.
- Absolute positioning: Set exact values by adding
value2: "abs"
(WebSocket/POST) or using compatible ranges.
// Camera Control Value Ranges: // zoom: Relative -1 to 1, Absolute 0 to 2 (0=minimum zoom, 2=2x zoom) // focus: Relative -1 to 1, Absolute 0 to 1 (0=near, 1=far) // pan: Always absolute -1 to 1 (-1=left, 0=center, 1=right) // tilt: Relative -1 to 1, Absolute -1 to 1 (-1=down, 0=center, 1=up) // exposure: Relative -1 to 1, Absolute 0 to 1 (0=dark, 1=bright) // WebSocket Examples: // Relative: {"action": "zoom", "value": 0.1} // Zoom in 10% // Absolute: {"action": "zoom", "value": 1.5, "value2": "abs"} // Set zoom to 1.5x // HTTP POST Examples: // Relative: POST body: {"action": "focus", "value": -0.1} // Absolute: POST body: {"action": "exposure", "value": 0.8, "value2": "abs"} // Note: HTTP GET only supports relative adjustments
Custom Layout Format
When using the layout
command, you can provide a custom layout object or array:
// Single layout example { "action": "layout", "value": [ {"x": 0, "y": 0, "w": 50, "h": 100, "slot": 0}, {"x": 50, "y": 0, "w": 50, "h": 100, "slot": 1} ] } // Using URL parameter to define multiple layouts // ?layouts=[[{"x":0,"y":0,"w":100,"h":100,"slot":0}],[{"x":0,"y":0,"w":50,"h":100,"slot":0},{"x":50,"y":0,"w":50,"h":100,"slot":1}]] // Layout properties: // x, y: Position (percentage of container) // w, h: Width and height (percentage of container) // slot: Guest slot number (0-indexed) // c: Crop to fit (true/false) // z: Z-index (layer) // To switch layouts: // {"action": "layout", "value": 0} // Auto-mix // {"action": "layout", "value": 1} // First custom layout // {"action": "layout", "value": 2} // Second custom layout