Compare commits
10 commits
9c0a8765ce
...
ba66bd743a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ba66bd743a | ||
|
|
e423bd4bf6 | ||
|
|
6fcd7f0317 | ||
|
|
53fd2ebd3d | ||
|
|
47ddf3552f | ||
|
|
8eb38b6c40 | ||
|
|
5ad7289977 | ||
|
|
47de0198a5 | ||
|
|
a36b06a4a5 | ||
|
|
43fc71c0ca |
8 changed files with 1910 additions and 1252 deletions
12
BMDevice.js
12
BMDevice.js
|
|
@ -245,6 +245,18 @@ class BMCamera extends BMDevice {
|
|||
doAutoWhitebalance() {
|
||||
this.PUTdata("/video/whiteBalance/doAuto");
|
||||
}
|
||||
|
||||
// gamut and gamma can each be null to leave the other unchanged
|
||||
setColorScience(gamut, gamma) {
|
||||
const data = {};
|
||||
if (gamut !== null && gamut !== undefined) data.gamut = gamut;
|
||||
if (gamma !== null && gamma !== undefined) data.gamma = gamma;
|
||||
if (Object.keys(data).length) this.PUTdata("/video/colorScience", data);
|
||||
}
|
||||
|
||||
setVideoFormat(data) {
|
||||
this.PUTdata("/system/format", data);
|
||||
}
|
||||
}
|
||||
|
||||
/* Helper Functions */
|
||||
|
|
|
|||
22
PRODUCT.md
Normal file
22
PRODUCT.md
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
# BM Camera Control WebUI
|
||||
|
||||
## Product Purpose
|
||||
A browser-based remote control panel for Blackmagic Design cameras via the official REST API over a local network. Used on set to adjust camera parameters without touching the camera body.
|
||||
|
||||
## Users
|
||||
- Camera operators: need one-tap access to recording state and exposure controls
|
||||
- DITs (Digital Imaging Technicians): need color science selection, color correction, and format settings
|
||||
- Directors / ACs: need timecode and recording status visible at a glance
|
||||
- All users may be working in dim environments (video village, studio) and on tablets
|
||||
|
||||
## Register
|
||||
product
|
||||
|
||||
## Tone
|
||||
Clinical and fast. Every control earns its place. No decorative chrome. Quiet when nothing is happening; clear when something requires attention (especially recording state).
|
||||
|
||||
## Anti-references
|
||||
- Neon SaaS dashboards
|
||||
- Consumer camera apps (bright white, rounded, playful)
|
||||
- Generic Bootstrap-dark or shadcn defaults
|
||||
- Glassmorphism decoration
|
||||
|
|
@ -22,7 +22,7 @@ If your camera does not have an ethernet port, use a USB-C to ethernet adapter.
|
|||
|
||||

|
||||
|
||||
> If you're using the GitHub Pages site, the API must be accessed with HTTPS rather than HTTP. You can enable this on the camera in **Blackmagic Camera Setup** by clicking the "Generate Certificate" button.
|
||||
> If you're using the GitHub Pages site, the API must be accessed with HTTPS rather than HTTP. You can enable this on the camera in **Blackmagic Camera Setup** by clicking the "Generate Certificate" button. You might have to convince your browser to trust the certificate by navigating to the API endpoint, overriding your browser's "this page isn't secure!" warnings, and then going back to the WebUI and connecting with HTTPS.
|
||||
|
||||
## Launching the App
|
||||
The app is a self-contained, offline web page. (No installation, dependencies, or servers to worry about!) Simply open the `index.html` file in your browser of choice, enter the hostname of your camera, and press "Connect".
|
||||
|
|
@ -49,6 +49,9 @@ Because the app is just a web page, you can open it in multiple browser windows
|
|||
|
||||
<img src="screenshots/WebUI2.png" width=30%>
|
||||
|
||||
### Tablet Screens
|
||||
If you're having trouble seeing the bottom of the controls because of the footer (which can happen on tablets), just tap on the footer bar to hide it. Tap on the header bar to bring the footer back.
|
||||
|
||||
### Data Synchronization
|
||||
The app uses WebSockets to keep itself updated with the latest info from the camera. If something has gone wrong, refresh the page.
|
||||
|
||||
|
|
@ -142,6 +145,7 @@ If you're having trouble and don't know why, check the browser console.
|
|||
- Save / download preset files to/from the camera
|
||||
|
||||
### For License and Copyright details, See `LICENSE.txt`
|
||||
(c) 2024 Dylan Speiser
|
||||
First made in 2024 by Dylan Speiser
|
||||
Big thank you to all contributors!
|
||||
<br>
|
||||
Licensed under the GNU General Public License
|
||||
|
|
|
|||
837
index.html
837
index.html
|
|
@ -1,349 +1,552 @@
|
|||
<!-- (c) 2024 Dylan Speiser -->
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<!-- Page title and metadata -->
|
||||
<title>Camera Control WebUI for Blackmagic Cameras</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="description" content="JS-based web interface for controlling Blackmagic Design cameras via the official REST API">
|
||||
<meta name="author" content="Dylan Speiser">
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>BM Camera Control</title>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
</head>
|
||||
<body onload="bodyOnLoad()">
|
||||
<script src="BMDevice.js"></script>
|
||||
<script src="web-ui.js"></script>
|
||||
|
||||
<!-- Linking the stylesheet -->
|
||||
<link rel="stylesheet" href="style.css">
|
||||
</head>
|
||||
<body onload="bodyOnLoad()">
|
||||
<!-- JavaScript Linking -->
|
||||
<script src="BMDevice.js"></script>
|
||||
<script src="web-ui.js"></script>
|
||||
<!-- Background logo watermark -->
|
||||
<div id="bgLogo" aria-hidden="true">
|
||||
<img src="resources/wilddragon-logo.svg" alt="">
|
||||
</div>
|
||||
|
||||
<!------ Page Content ------>
|
||||
|
||||
<!-- Header Div -->
|
||||
<div class="flexContainerH" id="headerContainer">
|
||||
<h1>Camera Control WebUI for Blackmagic Cameras</h1>
|
||||
<!-- Top Bar -->
|
||||
<header id="topBar">
|
||||
<div id="camInfo">
|
||||
<span id="cameraName">NOT CONNECTED</span>
|
||||
<span id="timecodeLabel" class="timecode">--:--:--:--</span>
|
||||
</div>
|
||||
|
||||
<!-- Camera Select Bar -->
|
||||
<div class="flexContainerH" id="cameraSelectContainer">
|
||||
<span class="cameraSwitchLabel selectedCam"><a href="#" onclick="switchCamera(0)">CAM1</a></span>
|
||||
<span class="camSelectSeparator">|</span>
|
||||
<span class="cameraSwitchLabel"><a href="#" onclick="switchCamera(1)">CAM2</a></span>
|
||||
<span class="camSelectSeparator">|</span>
|
||||
<span class="cameraSwitchLabel"><a href="#" onclick="switchCamera(2)">CAM3</a></span>
|
||||
<span class="camSelectSeparator">|</span>
|
||||
<span class="cameraSwitchLabel"><a href="#" onclick="switchCamera(3)">CAM4</a></span>
|
||||
<span class="camSelectSeparator">|</span>
|
||||
<span class="cameraSwitchLabel"><a href="#" onclick="switchCamera(4)">CAM5</a></span>
|
||||
<span class="camSelectSeparator">|</span>
|
||||
<span class="cameraSwitchLabel"><a href="#" onclick="switchCamera(5)">CAM6</a></span>
|
||||
<span class="camSelectSeparator">|</span>
|
||||
<span class="cameraSwitchLabel"><a href="#" onclick="switchCamera(6)">CAM7</a></span>
|
||||
<span class="camSelectSeparator">|</span>
|
||||
<span class="cameraSwitchLabel"><a href="#" onclick="switchCamera(7)">CAM8</a></span>
|
||||
<div id="formatDisplay">
|
||||
<span id="formatCodec">—</span>
|
||||
<span id="formatResolution">—</span>
|
||||
<span id="formatFPS">—</span>
|
||||
</div>
|
||||
|
||||
<!-- Camera Controls Box -->
|
||||
<div class="flexContainerH" id="allCamerasContainer">
|
||||
<div class="flexContainerV" id="cameraControlsContainer">
|
||||
<div class="flexContainerH" id="cameraControlHeadContainer">
|
||||
<h2 id="cameraNumberLabel">CAM1</h2>
|
||||
</div>
|
||||
<div id="transportControls">
|
||||
<button class="iconBtn" onclick="loopHandler('Loop')" title="Loop" id="loopButton">↻</button>
|
||||
<button class="iconBtn" onclick="loopHandler('Single Clip')" title="Single Clip" id="singleClipButton">S</button>
|
||||
<button class="iconBtn" onclick="cameras[ci].seek(false)" title="Previous">⏴</button>
|
||||
<button class="iconBtn" onclick="cameras[ci].play()" title="Play">▶</button>
|
||||
<button class="iconBtn" onclick="cameras[ci].stop()" title="Stop">⏹</button>
|
||||
<button class="iconBtn" onclick="cameras[ci].seek(true)" title="Next">⏵</button>
|
||||
</div>
|
||||
|
||||
<div class="flexContainerH" id="cameraControlColorCorrectionContainer">
|
||||
<!-- <div class="flexContainerH" id="cameraControlLGGTabs">
|
||||
<a href="#" class="ccTabLabel selectedTab" onclick="">Lift</a>
|
||||
<a href="#" class="ccTabLabel" onclick="">Gamma</a>
|
||||
<a href="#" class="ccTabLabel" onclick="">Gain</a>
|
||||
</div> -->
|
||||
<span style="margin-top: 0.5em;">Lift</span>
|
||||
<div class="flexContainerH" id="cameraControlColorCorrectionBottomContainer">
|
||||
<button class="CCResetButton circleButton" onclick="resetCC(0)" title="Reset Lift">⟳</button>
|
||||
<div class="flexContainerH" id="cameraControlColorCorrectionNumbersContainer">
|
||||
<span contenteditable="plaintext-only" style="text-decoration-color: #dbdbdb;" class="CClumaLabel" onmousedown="CCInputHandler(0)" onkeydown="CCInputHandler(0)">0.00</span>
|
||||
<span contenteditable="plaintext-only" style="text-decoration-color: #e64b3d;" class="CCredLabel" onmousedown="CCInputHandler(0)" onkeydown="CCInputHandler(0)">0.00</span>
|
||||
<span contenteditable="plaintext-only" style="text-decoration-color: #00a841;" class="CCgreenLabel" onmousedown="CCInputHandler(0)" onkeydown="CCInputHandler(0)">0.00</span>
|
||||
<span contenteditable="plaintext-only" style="text-decoration-color: #2a78c8;" class="CCblueLabel" onmousedown="CCInputHandler(0)" onkeydown="CCInputHandler(0)">0.00</span>
|
||||
</div>
|
||||
<button id="CCHamburgerButton" class="circleButton" onclick="setCCFromUI(0)" title="Set Lift">➚</button>
|
||||
</div>
|
||||
<button id="recordButton" onclick="cameras[ci].toggleRecord()" title="Toggle Record">
|
||||
<span id="recDot"></span>
|
||||
<span id="recLabel">REC</span>
|
||||
</button>
|
||||
</header>
|
||||
|
||||
<span>Gamma</span>
|
||||
<div class="flexContainerH" id="cameraControlColorCorrectionBottomContainer">
|
||||
<button class="CCResetButton circleButton" onclick="resetCC(1)" title="Reset Gamma">⟳</button>
|
||||
<div class="flexContainerH" id="cameraControlColorCorrectionNumbersContainer">
|
||||
<span contenteditable="plaintext-only" style="text-decoration-color: #dbdbdb;" class="CClumaLabel" onmousedown="CCInputHandler(1)" onkeydown="CCInputHandler(1)">0.00</span>
|
||||
<span contenteditable="plaintext-only" style="text-decoration-color: #e64b3d;" class="CCredLabel" onmousedown="CCInputHandler(1)" onkeydown="CCInputHandler(1)">0.00</span>
|
||||
<span contenteditable="plaintext-only" style="text-decoration-color: #00a841;" class="CCgreenLabel" onmousedown="CCInputHandler(1)" onkeydown="CCInputHandler(1)">0.00</span>
|
||||
<span contenteditable="plaintext-only" style="text-decoration-color: #2a78c8;" class="CCblueLabel" onmousedown="CCInputHandler(1)" onkeydown="CCInputHandler(1)">0.00</span>
|
||||
</div>
|
||||
<button id="CCHamburgerButton" class="circleButton" onclick="setCCFromUI(1)" title="Set Gamma">➚</button>
|
||||
</div>
|
||||
<!-- Tab Bar -->
|
||||
<nav id="tabBar">
|
||||
<button class="tab active" onclick="switchTab('exposure')" id="tab-btn-exposure">Exposure</button>
|
||||
<button class="tab" onclick="switchTab('colorscience')" id="tab-btn-colorscience">Color Science</button>
|
||||
<button class="tab" onclick="switchTab('colorcorrection')" id="tab-btn-colorcorrection">Color Correction</button>
|
||||
<button class="tab" onclick="switchTab('lens')" id="tab-btn-lens">Lens</button>
|
||||
<button class="tab" onclick="switchTab('system')" id="tab-btn-system">System</button>
|
||||
</nav>
|
||||
|
||||
<span>Gain</span>
|
||||
<div class="flexContainerH" id="cameraControlColorCorrectionBottomContainer">
|
||||
<button class="CCResetButton circleButton" onclick="resetCC(2)" title="Reset Gain">⟳</button>
|
||||
<div class="flexContainerH" id="cameraControlColorCorrectionNumbersContainer">
|
||||
<span contenteditable="plaintext-only" style="text-decoration-color: #dbdbdb;" class="CClumaLabel" onmousedown="CCInputHandler(2)" onkeydown="CCInputHandler(2)">0.00</span>
|
||||
<span contenteditable="plaintext-only" style="text-decoration-color: #e64b3d;" class="CCredLabel" onmousedown="CCInputHandler(2)" onkeydown="CCInputHandler(2)">0.00</span>
|
||||
<span contenteditable="plaintext-only" style="text-decoration-color: #00a841;" class="CCgreenLabel" onmousedown="CCInputHandler(2)" onkeydown="CCInputHandler(2)">0.00</span>
|
||||
<span contenteditable="plaintext-only" style="text-decoration-color: #2a78c8;" class="CCblueLabel" onmousedown="CCInputHandler(2)" onkeydown="CCInputHandler(2)">0.00</span>
|
||||
</div>
|
||||
<button id="CCHamburgerButton" class="circleButton" onclick="setCCFromUI(2)" title="Set Gain">➚</button>
|
||||
</div>
|
||||
|
||||
<!-- ======== MAIN CONTENT ======== -->
|
||||
<main id="mainContent">
|
||||
|
||||
<span>Offset</span>
|
||||
<div class="flexContainerH" id="cameraControlColorCorrectionBottomContainer">
|
||||
<button class="CCResetButton circleButton" onclick="resetCC(3)" title="Reset Offset">⟳</button>
|
||||
<div class="flexContainerH" id="cameraControlColorCorrectionNumbersContainer">
|
||||
<span contenteditable="plaintext-only" style="text-decoration-color: #dbdbdb;" class="CClumaLabel" onmousedown="CCInputHandler(3)" onkeydown="CCInputHandler(3)">0.00</span>
|
||||
<span contenteditable="plaintext-only" style="text-decoration-color: #e64b3d;" class="CCredLabel" onmousedown="CCInputHandler(3)" onkeydown="CCInputHandler(3)">0.00</span>
|
||||
<span contenteditable="plaintext-only" style="text-decoration-color: #00a841;" class="CCgreenLabel" onmousedown="CCInputHandler(3)" onkeydown="CCInputHandler(3)">0.00</span>
|
||||
<span contenteditable="plaintext-only" style="text-decoration-color: #2a78c8;" class="CCblueLabel" onmousedown="CCInputHandler(3)" onkeydown="CCInputHandler(3)">0.00</span>
|
||||
</div>
|
||||
<button id="CCHamburgerButton" class="circleButton" onclick="setCCFromUI(4)" title="Set Offset">➚</button>
|
||||
<!-- ===== EXPOSURE PANEL ===== -->
|
||||
<section id="tab-exposure" class="tabPanel active">
|
||||
<div class="exposureRow">
|
||||
|
||||
<div class="expPill">
|
||||
<span class="expPillLabel">ISO</span>
|
||||
<div class="expPillValue">
|
||||
<button class="adjBtn" onclick="adjustISO(-100)">◀</button>
|
||||
<span id="ISODisplay" class="expValue" contenteditable="plaintext-only"
|
||||
onkeydown="ISOKeyHandler(event)" onblur="ISOBlurHandler()">—</span>
|
||||
<button class="adjBtn" onclick="adjustISO(100)">▶</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flexContainerH" id="cameraControlExposureContainer">
|
||||
<div class="ccExposureSettingContainer">
|
||||
<span class="exposureControlLabel">FILTER</span>
|
||||
<div class="ccExposureSettingValueContainer">
|
||||
<a class="expAdjArr" href="#" onclick="decreaseND()" id="NDL">◀</a>
|
||||
<span id="ndFilterSpan" contenteditable="plaintext-only" onkeydown="NDFilterInputHandler()" onmousedown="NDFilterInputHandler()">0</span>
|
||||
<a class="expAdjArr" href="#" onclick="increaseND()" id="NDR">▶</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ccExposureSettingContainer">
|
||||
<span class="exposureControlLabel">GAIN</span>
|
||||
<div class="ccExposureSettingValueContainer">
|
||||
<a class="expAdjArr" href="#" onclick="decreaseGain()" id="GAL">◀</a>
|
||||
<span id="gainSpan" contenteditable="plaintext-only" onkeydown="GainInputHandler()" onmousedown="GainInputHandler()">+0db</span>
|
||||
<a class="expAdjArr" href="#" onclick="increaseGain()" id="GAR">▶</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ccExposureSettingContainer">
|
||||
<span class="exposureControlLabel">SHUTTER</span>
|
||||
<div class="ccExposureSettingValueContainer">
|
||||
<a class="expAdjArr" href="#" onclick="decreaseShutter()" id="SHL">◀</a>
|
||||
<span id="shutterSpan" contenteditable="plaintext-only" onkeydown="handleShutterInput()" onmousedown="handleShutterInput()">1/50</span>
|
||||
<a class="expAdjArr" href="#" onclick="increaseShutter()" id="SHR">▶</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ccExposureSettingContainer">
|
||||
<span class="exposureControlLabel" onclick="swapWBMode()" title="Click here to swap between WB and Tint" id="WBLabel">BALANCE</span>
|
||||
<div class="ccExposureSettingValueContainer" id="WBValueContainer">
|
||||
<a class="expAdjArr" href="#" onclick="decreaseWhiteBalance()" id="WBL">◀</a>
|
||||
<span id="whiteBalanceSpan" contenteditable="plaintext-only" onkeydown="WBInputHandler()" onmousedown="WBInputHandler()">5600K</span>
|
||||
<a class="expAdjArr" href="#" onclick="increaseWhiteBalance()" id="WBR">▶</a>
|
||||
</div>
|
||||
<div class="ccExposureSettingValueContainer dNone" id="WBTintValueContainer">
|
||||
<a class="expAdjArr" href="#" onclick="decreaseWhiteBalanceTint()" id="WBTL">◀</a>
|
||||
<span id="whiteBalanceTintSpan" contenteditable="plaintext-only" onkeydown="WBTInputHandler()" onmousedown="WBTInputHandler()">0</span>
|
||||
<a class="expAdjArr" href="#" onclick="increaseWhiteBalanceTint()" id="WBLR">▶</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ccExposureSettingContainer">
|
||||
<button id="AWBButton" class="circleButton" title="Make the camera do an Auto Whitebalance" onclick="cameras[ci].doAutoWhitebalance()">AW</button>
|
||||
<div class="expPill">
|
||||
<span class="expPillLabel">SHUTTER</span>
|
||||
<div class="expPillValue">
|
||||
<button class="adjBtn" onclick="decreaseShutter()">◀</button>
|
||||
<span id="shutterDisplay" class="expValue" contenteditable="plaintext-only"
|
||||
onkeydown="handleShutterInput()" onmousedown="handleShutterInput()">—</span>
|
||||
<button class="adjBtn" onclick="increaseShutter()">▶</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flexContainerH" id="cameraControlLensContainer">
|
||||
<div class="lensSliderContainer">
|
||||
<span>FOCUS</span>
|
||||
<input type="range" orient="vertical" max="1" min="0" step="0.001" id="focusRange" oninput="cameras[ci].PUTdata('/lens/focus', {normalised: parseFloat(this.value)})">
|
||||
<button id="AFButton" class="circleButton" onclick="cameras[ci].doAutoFocus()">AF</button>
|
||||
</div>
|
||||
<div class="lensSliderContainer">
|
||||
<span>IRIS</span>
|
||||
<input type="range" orient="vertical" max="1" min="0" step="0.001" id="irisRange" oninput="cameras[ci].PUTdata('/lens/iris', {normalised: parseFloat(this.value)})">
|
||||
<span id="apertureStopsLabel">X.X</span>
|
||||
</div>
|
||||
<div class="lensSliderContainer">
|
||||
<span>ZOOM</span>
|
||||
<input type="range" orient="vertical" max="1" min="0" step="0.001" id="zoomRange" oninput="cameras[ci].PUTdata('/lens/zoom', {normalised: parseFloat(this.value)})">
|
||||
<span id="zoomMMLabel">XXmm</span>
|
||||
<div class="expPill">
|
||||
<span class="expPillLabel">ND FILTER</span>
|
||||
<div class="expPillValue">
|
||||
<button class="adjBtn" onclick="decreaseND()">◀</button>
|
||||
<span id="ndFilterDisplay" class="expValue" contenteditable="plaintext-only"
|
||||
onkeydown="NDFilterInputHandler()" onmousedown="NDFilterInputHandler()">—</span>
|
||||
<button class="adjBtn" onclick="increaseND()">▶</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="expPill">
|
||||
<span class="expPillLabel">GAIN</span>
|
||||
<div class="expPillValue">
|
||||
<button class="adjBtn" onclick="decreaseGain()">◀</button>
|
||||
<span id="gainDisplay" class="expValue" contenteditable="plaintext-only"
|
||||
onkeydown="GainInputHandler()" onmousedown="GainInputHandler()">—</span>
|
||||
<button class="adjBtn" onclick="increaseGain()">▶</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="expPill" id="wbPill">
|
||||
<span class="expPillLabel" id="WBLabel" onclick="swapWBMode()" title="Click to toggle WB / Tint"
|
||||
style="cursor:pointer">WB ↕</span>
|
||||
<div class="expPillValue" id="WBValueContainer">
|
||||
<button class="adjBtn" onclick="decreaseWhiteBalance()">◀</button>
|
||||
<span id="whiteBalanceDisplay" class="expValue" contenteditable="plaintext-only"
|
||||
onkeydown="WBInputHandler()" onmousedown="WBInputHandler()">—</span>
|
||||
<button class="adjBtn" onclick="increaseWhiteBalance()">▶</button>
|
||||
</div>
|
||||
<div class="expPillValue hidden" id="WBTintValueContainer">
|
||||
<button class="adjBtn" onclick="decreaseWhiteBalanceTint()">◀</button>
|
||||
<span id="whiteBalanceTintDisplay" class="expValue" contenteditable="plaintext-only"
|
||||
onkeydown="WBTInputHandler()" onmousedown="WBTInputHandler()">—</span>
|
||||
<button class="adjBtn" onclick="increaseWhiteBalanceTint()">▶</button>
|
||||
</div>
|
||||
<button class="awbBtn" onclick="cameras[ci].doAutoWhitebalance()" title="Auto White Balance">AWB</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="flexContainerV" id="cameraControlsContainerExpanded">
|
||||
<div class="flexContainerH" id="cameraControlExpandedHeadContainer">
|
||||
<h2 id="cameraName">CAMERA NAME</h2>
|
||||
<div id="formatDisplay">
|
||||
<span id="formatCodec">CODEC</span>
|
||||
<span id="formatResolution">RESOLUTION</span>
|
||||
<span id="formatFPS">FPS</span>
|
||||
</div>
|
||||
<div id="transportControls">
|
||||
<!-- These will be sticky buttons for loop, single clip, record -->
|
||||
<button class="circleButton" onclick="loopHandler('Loop')" title="Loop" id="loopButton">↻</button>
|
||||
<button class="circleButton" onclick="loopHandler('Single Clip')" title="Single Clip" id="singleClipButton">S</button>
|
||||
<button class="circleButton" onclick="cameras[ci].seek(false)" title="Back">⏴</button>
|
||||
<button class="circleButton" onclick="cameras[ci].seek(true)" title="Forward">⏵</button>
|
||||
<button class="circleButton" onclick="cameras[ci].toggleRecord()" title="Record" style="color: red;">⏺</button>
|
||||
<button class="circleButton" onclick="cameras[ci].play()" title="Play">▶</button>
|
||||
<button class="circleButton" onclick="cameras[ci].stop()" title="Stop">⏹</button>
|
||||
</div>
|
||||
<h2 id="timecodeLabel">TIMECODE</h2>
|
||||
<!-- AE Mode row -->
|
||||
<div class="settingsRow">
|
||||
<div class="settingGroup">
|
||||
<label class="settingLabel">AE MODE</label>
|
||||
<select id="AEmodeDropDown" class="settingSelect" onmousedown="unsavedChanges.push('AutoExposure')">
|
||||
<option value="Off">Off</option>
|
||||
<option value="Continuous">Continuous</option>
|
||||
<option value="OneShot">One-Shot</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="settingGroup">
|
||||
<label class="settingLabel">AE TYPE</label>
|
||||
<select id="AEtypeDropDown" class="settingSelect" onmousedown="unsavedChanges.push('AutoExposure')">
|
||||
<option value="">None</option>
|
||||
<option value="Iris">Iris Only</option>
|
||||
<option value="Shutter">Shutter Only</option>
|
||||
<option value="Shutter,Iris">Shutter + Iris</option>
|
||||
<option value="Iris,Shutter">Iris + Shutter</option>
|
||||
</select>
|
||||
</div>
|
||||
<button class="actionBtn" onclick="AEmodeInputHandler()">Set AE Mode</button>
|
||||
|
||||
<!-- WB Presets -->
|
||||
<div class="settingGroup" style="margin-left: auto;">
|
||||
<label class="settingLabel">WB PRESETS</label>
|
||||
<div class="presetBtnRow">
|
||||
<button class="presetBtn" onclick="cameras[ci].setWhiteBalancePreset(0)">Sun</button>
|
||||
<button class="presetBtn" onclick="cameras[ci].setWhiteBalancePreset(1)">Tungsten</button>
|
||||
<button class="presetBtn" onclick="cameras[ci].setWhiteBalancePreset(2)">Fluoro</button>
|
||||
<button class="presetBtn" onclick="cameras[ci].setWhiteBalancePreset(3)">Shade</button>
|
||||
<button class="presetBtn" onclick="cameras[ci].setWhiteBalancePreset(4)">Cloud</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flexContainerV" id="cameraControlExpandedBodyContainer">
|
||||
<div class="tableControl">
|
||||
<h3>Connection</h3>
|
||||
<table>
|
||||
<tr>
|
||||
<td>Hostname</td>
|
||||
<td>
|
||||
<input type="text" placeholder=" Camera-Name-Here.local" id="hostnameInput" onclick="hostnameInputHandler()" onkeydown="hostnameInputHandler()" style="text-align: left;">
|
||||
<button onclick="initCamera()">Connect</button>
|
||||
<input type="checkbox" id="secureCheckbox">
|
||||
<span id="secureCheckboxLabel">Use HTTPS</span>
|
||||
<span id="connectionErrorSpan"></span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Send API Call</td>
|
||||
<td>
|
||||
<input type="radio" id="requestTypeGET" value="GET" name="manualRequestType" checked>
|
||||
<label for="requestTypeGET">GET</label>
|
||||
<input type="radio" id="requestTypePUT" value="PUT" name="manualRequestType">
|
||||
<label for="requestTypePUT">PUT</label>
|
||||
<!-- ISO direct input -->
|
||||
<div class="settingsRow">
|
||||
<div class="settingGroup">
|
||||
<label class="settingLabel">ISO (direct)</label>
|
||||
<input type="number" id="ISOInput" class="settingInput" step="100"
|
||||
onkeydown="ISOInputHandler()" onmousedown="unsavedChanges.push('ISO')">
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<input type="text" id="manualRequestEndpointLabel" placeholder="request endpoint">
|
||||
<input type="text" id="manualRequestBodyLabel" placeholder="request body">
|
||||
|
||||
<button onclick="manualAPICall()">Send API Request</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<p id="manualRequestResponseP">Send manual API requests using the above controls. See <a href="https://documents.blackmagicdesign.com/DeveloperManuals/RESTAPIforBlackmagicCameras.pdf?_v=1696143610000" target="_blank" style="color: #6e6e6e;">documentation</a> for details.</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<!-- ===== COLOR SCIENCE PANEL (NEW) ===== -->
|
||||
<section id="tab-colorscience" class="tabPanel">
|
||||
|
||||
<div class="csGrid">
|
||||
<div class="csCard">
|
||||
<h3 class="csCardTitle">Gamma Curve</h3>
|
||||
<div class="csOptions" id="gammaOptions">
|
||||
<button class="csOptionBtn" data-gamma="Blackmagic Design Film" onclick="setGamma(this)">Film</button>
|
||||
<button class="csOptionBtn" data-gamma="Blackmagic Design Video" onclick="setGamma(this)">Video</button>
|
||||
<button class="csOptionBtn" data-gamma="Blackmagic Design Extended Video" onclick="setGamma(this)">Extended Video</button>
|
||||
<button class="csOptionBtn" data-gamma="Rec709" onclick="setGamma(this)">Rec.709</button>
|
||||
<button class="csOptionBtn" data-gamma="sRGB" onclick="setGamma(this)">sRGB</button>
|
||||
<button class="csOptionBtn" data-gamma="Linear" onclick="setGamma(this)">Linear</button>
|
||||
<button class="csOptionBtn" data-gamma="DaVinci Intermediate" onclick="setGamma(this)">DaVinci Intermediate</button>
|
||||
</div>
|
||||
<div class="csCurrentRow">
|
||||
<span class="csCurrentLabel">Current:</span>
|
||||
<span id="currentGamma" class="csCurrentValue">—</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="csCard">
|
||||
<h3 class="csCardTitle">Color Gamut</h3>
|
||||
<div class="csOptions" id="gamutOptions">
|
||||
<button class="csOptionBtn" data-gamut="Blackmagic Wide Gamut" onclick="setGamut(this)">BM Wide Gamut</button>
|
||||
<button class="csOptionBtn" data-gamut="Blackmagic Design" onclick="setGamut(this)">BM Design</button>
|
||||
<button class="csOptionBtn" data-gamut="Rec.2020" onclick="setGamut(this)">Rec.2020</button>
|
||||
<button class="csOptionBtn" data-gamut="Rec.709" onclick="setGamut(this)">Rec.709</button>
|
||||
<button class="csOptionBtn" data-gamut="sRGB" onclick="setGamut(this)">sRGB</button>
|
||||
<button class="csOptionBtn" data-gamut="DCI-P3" onclick="setGamut(this)">DCI-P3</button>
|
||||
<button class="csOptionBtn" data-gamut="Display P3" onclick="setGamut(this)">Display P3</button>
|
||||
</div>
|
||||
<div class="csCurrentRow">
|
||||
<span class="csCurrentLabel">Current:</span>
|
||||
<span id="currentGamut" class="csCurrentValue">—</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="csCard csCard--full">
|
||||
<h3 class="csCardTitle">Quick Presets</h3>
|
||||
<div class="csQuickPresets">
|
||||
<button class="csQuickBtn" onclick="applyColorSciencePreset('braw-film')">
|
||||
<span class="csQuickBtnName">BRAW Film</span>
|
||||
<span class="csQuickBtnDetail">BM Wide Gamut + Film</span>
|
||||
</button>
|
||||
<button class="csQuickBtn" onclick="applyColorSciencePreset('braw-video')">
|
||||
<span class="csQuickBtnName">BRAW Video</span>
|
||||
<span class="csQuickBtnDetail">BM Design + Video</span>
|
||||
</button>
|
||||
<button class="csQuickBtn" onclick="applyColorSciencePreset('braw-ext')">
|
||||
<span class="csQuickBtnName">BRAW Ext. Video</span>
|
||||
<span class="csQuickBtnDetail">BM Design + Ext. Video</span>
|
||||
</button>
|
||||
<button class="csQuickBtn" onclick="applyColorSciencePreset('rec709')">
|
||||
<span class="csQuickBtnName">Rec.709</span>
|
||||
<span class="csQuickBtnDetail">Rec.709 + Rec709</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Video Format / Mode -->
|
||||
<div class="sectionDivider">
|
||||
<span>Video Format</span>
|
||||
</div>
|
||||
|
||||
<div class="formatGrid">
|
||||
<div class="settingGroup">
|
||||
<label class="settingLabel">CODEC</label>
|
||||
<select id="codecSelect" class="settingSelect">
|
||||
<option value="">— current —</option>
|
||||
<option value="BRAW 12:1">BRAW 12:1</option>
|
||||
<option value="BRAW 8:1">BRAW 8:1</option>
|
||||
<option value="BRAW 5:1">BRAW 5:1</option>
|
||||
<option value="BRAW 3:1">BRAW 3:1</option>
|
||||
<option value="H.265 High">H.265 High</option>
|
||||
<option value="H.265 Medium">H.265 Medium</option>
|
||||
<option value="H.265 Low">H.265 Low</option>
|
||||
<option value="H.264 High">H.264 High</option>
|
||||
<option value="H.264 Medium">H.264 Medium</option>
|
||||
<option value="H.264 Low">H.264 Low</option>
|
||||
<option value="ProRes 422 HQ">ProRes 422 HQ</option>
|
||||
<option value="ProRes 422">ProRes 422</option>
|
||||
<option value="ProRes 422 LT">ProRes 422 LT</option>
|
||||
<option value="ProRes 422 Proxy">ProRes 422 Proxy</option>
|
||||
<option value="ProRes 4444 XQ">ProRes 4444 XQ</option>
|
||||
<option value="DNxHR">DNxHR</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="settingGroup">
|
||||
<label class="settingLabel">FRAME RATE</label>
|
||||
<select id="frameRateSelect" class="settingSelect">
|
||||
<option value="">— current —</option>
|
||||
<option value="23.98">23.98</option>
|
||||
<option value="24">24</option>
|
||||
<option value="25">25</option>
|
||||
<option value="29.97">29.97</option>
|
||||
<option value="30">30</option>
|
||||
<option value="47.95">47.95</option>
|
||||
<option value="48">48</option>
|
||||
<option value="50">50</option>
|
||||
<option value="59.94">59.94</option>
|
||||
<option value="60">60</option>
|
||||
<option value="120">120</option>
|
||||
</select>
|
||||
</div>
|
||||
<button class="actionBtn" onclick="applyVideoFormat()">Set Format</button>
|
||||
<span id="formatSetStatus" class="statusNote"></span>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
<!-- ===== COLOR CORRECTION PANEL ===== -->
|
||||
<section id="tab-colorcorrection" class="tabPanel">
|
||||
|
||||
<div class="ccGrid">
|
||||
<!-- Lift -->
|
||||
<div class="ccRow">
|
||||
<span class="ccRowLabel">Lift</span>
|
||||
<div class="ccChannels">
|
||||
<div class="ccChannel">
|
||||
<span class="ccChLabel" style="color: var(--ch-luma)">L</span>
|
||||
<span class="CClumaLabel ccVal" contenteditable="plaintext-only"
|
||||
onmousedown="CCInputHandler(0)" onkeydown="CCInputHandler(0)">0.00</span>
|
||||
</div>
|
||||
|
||||
<div class="tableControl">
|
||||
<h3>Presets</h3>
|
||||
<table>
|
||||
<tr>
|
||||
<td>Preset Select</td>
|
||||
<td>
|
||||
<select id="presetsDropDown" onmousedown="unsavedChanges.push('presets')" onchange="presetInputHandler()">
|
||||
<!-- Auto-populated by updateUIPresets() -->
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<button onclick="presetInputHandler()">Restore from Preset</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div class="ccChannel">
|
||||
<span class="ccChLabel" style="color: var(--ch-red)">R</span>
|
||||
<span class="CCredLabel ccVal" contenteditable="plaintext-only"
|
||||
onmousedown="CCInputHandler(0)" onkeydown="CCInputHandler(0)">0.00</span>
|
||||
</div>
|
||||
|
||||
<div class="tableControl">
|
||||
<h3>Exposure</h3>
|
||||
<table>
|
||||
<tr>
|
||||
<td>ISO</td>
|
||||
<td><input type="number" id="ISOInput" step="100" onkeydown="ISOInputHandler()" onmousedown="unsavedChanges.push('ISO')"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>AE Mode</td>
|
||||
<td>
|
||||
<select id="AEmodeDropDown" onmousedown="unsavedChanges.push('AutoExposure')">
|
||||
<option value="Off">Off</option>
|
||||
<option value="Continuous">Continuous</option>
|
||||
<option value="OneShot">One-Shot</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>AE Type</td>
|
||||
<td>
|
||||
<select id="AEtypeDropDown" onmousedown="unsavedChanges.push('AutoExposure')">
|
||||
<option value="">None</option>
|
||||
<option value="Iris">Iris Only</option>
|
||||
<option value="Shutter">Shutter Only</option>
|
||||
<option value="Shutter,Iris">Shutter + Iris</option>
|
||||
<option value="Iris,Shutter">Iris + Shutter</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<button style="margin: 2vh 0 0 3.5vw;" onclick="AEmodeInputHandler()">Set AE Mode</button>
|
||||
<div class="ccChannel">
|
||||
<span class="ccChLabel" style="color: var(--ch-green)">G</span>
|
||||
<span class="CCgreenLabel ccVal" contenteditable="plaintext-only"
|
||||
onmousedown="CCInputHandler(0)" onkeydown="CCInputHandler(0)">0.00</span>
|
||||
</div>
|
||||
|
||||
<div class="tableControl">
|
||||
<h3>Contrast</h3>
|
||||
<table>
|
||||
<tr>
|
||||
<td>Pivot</td>
|
||||
<td><input type="range" max="1" min="0" step="0.001" id="CCcontrastPivotRange" oninput="cameras[ci].PUTdata('/colorCorrection/contrast', {pivot: parseFloat(this.value)}); unsavedChanges = unsavedChanges.filter((e) => {return !e.includes('CC4')});"></td>
|
||||
<td>
|
||||
<span id="CCcontrastPivotLabel" contenteditable="plaintext-only" onkeydown="CCInputHandler(4)" onmousedown="CCInputHandler(4)">0</span>
|
||||
</td>
|
||||
<td rowspan="2">
|
||||
<button class="CCResetButton circleButton" onclick="resetCC(4)" title="Reset Contrast">⟳</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Adjust</td>
|
||||
<td><input type="range" max="2" min="0" step="0.001" id="CCcontrastAdjustRange" oninput="cameras[ci].PUTdata('/colorCorrection/contrast', {adjust: parseFloat(this.value)}); unsavedChanges = unsavedChanges.filter((e) => {return !e.includes('CC4')});"></td>
|
||||
<td>
|
||||
<span id="CCcontrastAdjustLabel" contenteditable="plaintext-only" onkeydown="CCInputHandler(4)" onmousedown="CCInputHandler(4)">0</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="tableControl">
|
||||
<h3>Color</h3>
|
||||
<table>
|
||||
<tr>
|
||||
<td>Hue</td>
|
||||
<td><input type="range" max="1" min="-1" step="0.001" id="CChueRange" oninput="cameras[ci].PUTdata('/colorCorrection/color', {hue: parseFloat(this.value)}); unsavedChanges = unsavedChanges.filter((e) => {return !e.includes('CC5')});"></td>
|
||||
<td>
|
||||
<span id="CCcolorHueLabel" contenteditable="plaintext-only" onkeydown="CCInputHandler(5)" onmousedown="CCInputHandler(5)">0</span>
|
||||
</td>
|
||||
<td rowspan="3">
|
||||
<button class="CCResetButton circleButton" onclick="resetCC(5)" title="Reset Color">⟳</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Saturation</td>
|
||||
<td><input type="range" max="2" min="0" step="0.001" id="CCsaturationRange" oninput="cameras[ci].PUTdata('/colorCorrection/color', {saturation: parseFloat(this.value)}); unsavedChanges = unsavedChanges.filter((e) => {return !e.includes('CC5')});"></td>
|
||||
<td>
|
||||
<span id="CCcolorSatLabel" contenteditable="plaintext-only" onkeydown="CCInputHandler(5)" onmousedown="CCInputHandler(5)">0</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Luma Contribution</td>
|
||||
<td><input type="range" max="1" min="0" step="0.001" id="CClumaContributionRange" oninput="cameras[ci].PUTdata('/colorCorrection/lumaContribution', {lumaContribution: parseFloat(this.value)}); unsavedChanges = unsavedChanges.filter((e) => {return !e.includes('CC5')});"></td>
|
||||
<td>
|
||||
<span id="CCcolorLCLabel" contenteditable="plaintext-only" onkeydown="CCInputHandler(5)" onmousedown="CCInputHandler(5)">0</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div class="ccChannel">
|
||||
<span class="ccChLabel" style="color: var(--ch-blue)">B</span>
|
||||
<span class="CCblueLabel ccVal" contenteditable="plaintext-only"
|
||||
onmousedown="CCInputHandler(0)" onkeydown="CCInputHandler(0)">0.00</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<button class="ccApplyBtn" onclick="setCCFromUI(0)" title="Apply">➚</button>
|
||||
<button class="ccResetBtn" onclick="resetCC(0)" title="Reset">⟳</button>
|
||||
</div>
|
||||
|
||||
<!-- Footer Div -->
|
||||
<div class="flexContainerH" id="footerContainer">
|
||||
<div id="footerLeft">
|
||||
<span class="">(v 1.3)</span>
|
||||
<span id="activeElementSpan"></span>
|
||||
<!-- Gamma -->
|
||||
<div class="ccRow">
|
||||
<span class="ccRowLabel">Gamma</span>
|
||||
<div class="ccChannels">
|
||||
<div class="ccChannel">
|
||||
<span class="ccChLabel" style="color: var(--ch-luma)">L</span>
|
||||
<span class="CClumaLabel ccVal" contenteditable="plaintext-only"
|
||||
onmousedown="CCInputHandler(1)" onkeydown="CCInputHandler(1)">0.00</span>
|
||||
</div>
|
||||
<div class="ccChannel">
|
||||
<span class="ccChLabel" style="color: var(--ch-red)">R</span>
|
||||
<span class="CCredLabel ccVal" contenteditable="plaintext-only"
|
||||
onmousedown="CCInputHandler(1)" onkeydown="CCInputHandler(1)">0.00</span>
|
||||
</div>
|
||||
<div class="ccChannel">
|
||||
<span class="ccChLabel" style="color: var(--ch-green)">G</span>
|
||||
<span class="CCgreenLabel ccVal" contenteditable="plaintext-only"
|
||||
onmousedown="CCInputHandler(1)" onkeydown="CCInputHandler(1)">0.00</span>
|
||||
</div>
|
||||
<div class="ccChannel">
|
||||
<span class="ccChLabel" style="color: var(--ch-blue)">B</span>
|
||||
<span class="CCblueLabel ccVal" contenteditable="plaintext-only"
|
||||
onmousedown="CCInputHandler(1)" onkeydown="CCInputHandler(1)">0.00</span>
|
||||
</div>
|
||||
</div>
|
||||
<button class="ccApplyBtn" onclick="setCCFromUI(1)" title="Apply">➚</button>
|
||||
<button class="ccResetBtn" onclick="resetCC(1)" title="Reset">⟳</button>
|
||||
</div>
|
||||
|
||||
<!-- Gain -->
|
||||
<div class="ccRow">
|
||||
<span class="ccRowLabel">Gain</span>
|
||||
<div class="ccChannels">
|
||||
<div class="ccChannel">
|
||||
<span class="ccChLabel" style="color: var(--ch-luma)">L</span>
|
||||
<span class="CClumaLabel ccVal" contenteditable="plaintext-only"
|
||||
onmousedown="CCInputHandler(2)" onkeydown="CCInputHandler(2)">1.00</span>
|
||||
</div>
|
||||
<div class="ccChannel">
|
||||
<span class="ccChLabel" style="color: var(--ch-red)">R</span>
|
||||
<span class="CCredLabel ccVal" contenteditable="plaintext-only"
|
||||
onmousedown="CCInputHandler(2)" onkeydown="CCInputHandler(2)">1.00</span>
|
||||
</div>
|
||||
<div class="ccChannel">
|
||||
<span class="ccChLabel" style="color: var(--ch-green)">G</span>
|
||||
<span class="CCgreenLabel ccVal" contenteditable="plaintext-only"
|
||||
onmousedown="CCInputHandler(2)" onkeydown="CCInputHandler(2)">1.00</span>
|
||||
</div>
|
||||
<div class="ccChannel">
|
||||
<span class="ccChLabel" style="color: var(--ch-blue)">B</span>
|
||||
<span class="CCblueLabel ccVal" contenteditable="plaintext-only"
|
||||
onmousedown="CCInputHandler(2)" onkeydown="CCInputHandler(2)">1.00</span>
|
||||
</div>
|
||||
</div>
|
||||
<button class="ccApplyBtn" onclick="setCCFromUI(2)" title="Apply">➚</button>
|
||||
<button class="ccResetBtn" onclick="resetCC(2)" title="Reset">⟳</button>
|
||||
</div>
|
||||
|
||||
<!-- Offset -->
|
||||
<div class="ccRow">
|
||||
<span class="ccRowLabel">Offset</span>
|
||||
<div class="ccChannels">
|
||||
<div class="ccChannel">
|
||||
<span class="ccChLabel" style="color: var(--ch-luma)">L</span>
|
||||
<span class="CClumaLabel ccVal" contenteditable="plaintext-only"
|
||||
onmousedown="CCInputHandler(3)" onkeydown="CCInputHandler(3)">0.00</span>
|
||||
</div>
|
||||
<div class="ccChannel">
|
||||
<span class="ccChLabel" style="color: var(--ch-red)">R</span>
|
||||
<span class="CCredLabel ccVal" contenteditable="plaintext-only"
|
||||
onmousedown="CCInputHandler(3)" onkeydown="CCInputHandler(3)">0.00</span>
|
||||
</div>
|
||||
<div class="ccChannel">
|
||||
<span class="ccChLabel" style="color: var(--ch-green)">G</span>
|
||||
<span class="CCgreenLabel ccVal" contenteditable="plaintext-only"
|
||||
onmousedown="CCInputHandler(3)" onkeydown="CCInputHandler(3)">0.00</span>
|
||||
</div>
|
||||
<div class="ccChannel">
|
||||
<span class="ccChLabel" style="color: var(--ch-blue)">B</span>
|
||||
<span class="CCblueLabel ccVal" contenteditable="plaintext-only"
|
||||
onmousedown="CCInputHandler(3)" onkeydown="CCInputHandler(3)">0.00</span>
|
||||
</div>
|
||||
</div>
|
||||
<button class="ccApplyBtn" onclick="setCCFromUI(3)" title="Apply">➚</button>
|
||||
<button class="ccResetBtn" onclick="resetCC(3)" title="Reset">⟳</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="footerLinks">
|
||||
<span><a id="documentationLink" href="#" target="_blank">YAML Documentation</a></span>
|
||||
<span><a id="mediaManagerLink" href="#" target="_blank">Web Media Manager</a></span>
|
||||
<span><a id="githubLink" href="https://github.com/DylanSpeiser/BM-Camera-Control-WebUI" target="_blank">GitHub</a></span>
|
||||
|
||||
<!-- Contrast -->
|
||||
<div class="sectionDivider"><span>Contrast</span></div>
|
||||
<div class="sliderGroup">
|
||||
<div class="sliderRow">
|
||||
<label class="sliderLabel">Pivot</label>
|
||||
<input type="range" class="slider" max="1" min="0" step="0.001" id="CCcontrastPivotRange"
|
||||
oninput="cameras[ci].PUTdata('/colorCorrection/contrast', {pivot: parseFloat(this.value)}); unsavedChanges = unsavedChanges.filter(e => !e.includes('CC4'));">
|
||||
<span id="CCcontrastPivotLabel" class="sliderVal" contenteditable="plaintext-only"
|
||||
onkeydown="CCInputHandler(4)" onmousedown="CCInputHandler(4)">0.50</span>
|
||||
</div>
|
||||
<div class="sliderRow">
|
||||
<label class="sliderLabel">Adjust</label>
|
||||
<input type="range" class="slider" max="2" min="0" step="0.001" id="CCcontrastAdjustRange"
|
||||
oninput="cameras[ci].PUTdata('/colorCorrection/contrast', {adjust: parseFloat(this.value)}); unsavedChanges = unsavedChanges.filter(e => !e.includes('CC4'));">
|
||||
<span id="CCcontrastAdjustLabel" class="sliderVal" contenteditable="plaintext-only"
|
||||
onkeydown="CCInputHandler(4)" onmousedown="CCInputHandler(4)">50%</span>
|
||||
</div>
|
||||
<button class="ccResetBtn" onclick="resetCC(4)" title="Reset Contrast">⟳</button>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
<!-- Hue / Sat / LC -->
|
||||
<div class="sectionDivider"><span>Color</span></div>
|
||||
<div class="sliderGroup">
|
||||
<div class="sliderRow">
|
||||
<label class="sliderLabel">Hue</label>
|
||||
<input type="range" class="slider" max="1" min="-1" step="0.001" id="CChueRange"
|
||||
oninput="cameras[ci].PUTdata('/colorCorrection/color', {hue: parseFloat(this.value)}); unsavedChanges = unsavedChanges.filter(e => !e.includes('CC5'));">
|
||||
<span id="CCcolorHueLabel" class="sliderVal" contenteditable="plaintext-only"
|
||||
onkeydown="CCInputHandler(5)" onmousedown="CCInputHandler(5)">180°</span>
|
||||
</div>
|
||||
<div class="sliderRow">
|
||||
<label class="sliderLabel">Saturation</label>
|
||||
<input type="range" class="slider" max="2" min="0" step="0.001" id="CCsaturationRange"
|
||||
oninput="cameras[ci].PUTdata('/colorCorrection/color', {saturation: parseFloat(this.value)}); unsavedChanges = unsavedChanges.filter(e => !e.includes('CC5'));">
|
||||
<span id="CCcolorSatLabel" class="sliderVal" contenteditable="plaintext-only"
|
||||
onkeydown="CCInputHandler(5)" onmousedown="CCInputHandler(5)">50%</span>
|
||||
</div>
|
||||
<div class="sliderRow">
|
||||
<label class="sliderLabel">Luma Contrib.</label>
|
||||
<input type="range" class="slider" max="1" min="0" step="0.001" id="CClumaContributionRange"
|
||||
oninput="cameras[ci].PUTdata('/colorCorrection/lumaContribution', {lumaContribution: parseFloat(this.value)}); unsavedChanges = unsavedChanges.filter(e => !e.includes('CC5'));">
|
||||
<span id="CCcolorLCLabel" class="sliderVal" contenteditable="plaintext-only"
|
||||
onkeydown="CCInputHandler(5)" onmousedown="CCInputHandler(5)">100%</span>
|
||||
</div>
|
||||
<button class="ccResetBtn" onclick="resetCC(5)" title="Reset Color">⟳</button>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
<!-- ===== LENS PANEL ===== -->
|
||||
<section id="tab-lens" class="tabPanel">
|
||||
<div class="lensGrid">
|
||||
|
||||
<div class="lensCard">
|
||||
<span class="lensCardLabel">FOCUS</span>
|
||||
<input type="range" class="vertSlider" orient="vertical" max="1" min="0" step="0.001"
|
||||
id="focusRange"
|
||||
oninput="cameras[ci].PUTdata('/lens/focus', {normalised: parseFloat(this.value)})">
|
||||
<button class="lensActionBtn" onclick="cameras[ci].doAutoFocus()">AF</button>
|
||||
</div>
|
||||
|
||||
<div class="lensCard">
|
||||
<span class="lensCardLabel">IRIS</span>
|
||||
<input type="range" class="vertSlider" orient="vertical" max="1" min="0" step="0.001"
|
||||
id="irisRange"
|
||||
oninput="cameras[ci].PUTdata('/lens/iris', {normalised: parseFloat(this.value)})">
|
||||
<span id="apertureStopsLabel" class="lensValueLabel">f/—</span>
|
||||
</div>
|
||||
|
||||
<div class="lensCard">
|
||||
<span class="lensCardLabel">ZOOM</span>
|
||||
<input type="range" class="vertSlider" orient="vertical" max="1" min="0" step="0.001"
|
||||
id="zoomRange"
|
||||
oninput="cameras[ci].PUTdata('/lens/zoom', {normalised: parseFloat(this.value)})">
|
||||
<span id="zoomMMLabel" class="lensValueLabel">—mm</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ===== SYSTEM PANEL ===== -->
|
||||
<section id="tab-system" class="tabPanel">
|
||||
|
||||
<div class="sysGrid">
|
||||
<div class="sysCard">
|
||||
<h3 class="sysCardTitle">Connection</h3>
|
||||
<div class="sysRow">
|
||||
<label class="settingLabel">Hostname / IP</label>
|
||||
<input type="text" id="hostnameInput" class="settingInput hostnameInput"
|
||||
placeholder="Camera-Name.local"
|
||||
onclick="hostnameInputHandler()" onkeydown="hostnameInputHandler()">
|
||||
</div>
|
||||
<div class="sysRow sysRow--inline">
|
||||
<input type="checkbox" id="secureCheckbox">
|
||||
<label for="secureCheckbox" class="settingLabel" style="cursor:pointer">Use HTTPS</label>
|
||||
<button class="actionBtn" onclick="initCamera()">Connect</button>
|
||||
<span id="connectionErrorSpan" class="statusNote"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sysCard">
|
||||
<h3 class="sysCardTitle">Presets</h3>
|
||||
<div class="sysRow sysRow--inline">
|
||||
<select id="presetsDropDown" class="settingSelect" style="flex:1"
|
||||
onmousedown="unsavedChanges.push('presets')" onchange="presetInputHandler()">
|
||||
</select>
|
||||
<button class="actionBtn" onclick="presetInputHandler()">Restore Preset</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sysCard sysCard--full">
|
||||
<h3 class="sysCardTitle">Manual API</h3>
|
||||
<div class="sysRow sysRow--inline">
|
||||
<label class="settingLabel">
|
||||
<input type="radio" id="requestTypeGET" value="GET" name="manualRequestType" checked>
|
||||
GET
|
||||
</label>
|
||||
<label class="settingLabel">
|
||||
<input type="radio" id="requestTypePUT" value="PUT" name="manualRequestType">
|
||||
PUT
|
||||
</label>
|
||||
<input type="text" id="manualRequestEndpointLabel" class="settingInput" placeholder="/endpoint">
|
||||
<input type="text" id="manualRequestBodyLabel" class="settingInput" placeholder="JSON body">
|
||||
<button class="actionBtn" onclick="manualAPICall()">Send</button>
|
||||
</div>
|
||||
<p id="manualRequestResponseP" class="apiResponse">
|
||||
See <a href="https://documents.blackmagicdesign.com/DeveloperManuals/RESTAPIforBlackmagicCameras.pdf?_v=1696143610000"
|
||||
target="_blank">BM REST API docs</a> for available endpoints.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="sysCard">
|
||||
<h3 class="sysCardTitle">Links</h3>
|
||||
<div class="linkRow">
|
||||
<a id="documentationLink" href="#" target="_blank" class="sysLink">YAML Docs</a>
|
||||
<a id="mediaManagerLink" href="#" target="_blank" class="sysLink">Web Media Manager</a>
|
||||
<a href="https://github.com/DylanSpeiser/BM-Camera-Control-WebUI" target="_blank" class="sysLink">GitHub</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
</main>
|
||||
|
||||
<!-- Status Bar -->
|
||||
<footer id="statusBar">
|
||||
<span id="activeElementSpan"></span>
|
||||
<span class="version">v1.5.0</span>
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
BIN
resources/wilddragon-logo.png
Normal file
BIN
resources/wilddragon-logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 91 KiB |
120
resources/wilddragon-logo.svg
Normal file
120
resources/wilddragon-logo.svg
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 24.3.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 1000 1000" style="enable-background:new 0 0 1000 1000;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#1025A1;}
|
||||
</style>
|
||||
<g>
|
||||
<g>
|
||||
<g transform="translate(192.760202, 192.018739)">
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M280,607.4c-76.3-6.3-92.6-71.7-83-105.7c0,0,36.2,14.7,49.9,49.5c0,0-1.5-31.2-13.8-40.1c0,0,91.5,22.6,87.6,81.3
|
||||
c0,0,28.8-40.5-19.8-85.6c-48.6-45-40.5-53.1-40.5-53.1s8.2-4.3,12.9-11.6l1.8,4.9c0,0,2.8-11.5,2.1-16.6c0,0,3.4,6,4.8,8.1
|
||||
c0,0-2.2-15.2-2.2-18.9c0-3.7,9.4-14.4,20.8-13c11.4,1.4,20.2-5.9,20.2-5.9l-1.7,6.7c0,0,6.8-6.8,11.7-7.3
|
||||
c4.9-0.4,14.3,2.2,11,4.6c-3,2.2,0.3,6.9,0.7,7.4c-0.2-0.5-2-4.4,2.5-6.8c4.8-2.6,11-4.1,8.2-9.9c0,0-1.8-5.5-7.1-8.5
|
||||
c0,0,1.7,3.1-0.7,3.1c-2.4,0-8.5-8.9-15.2-10.4l0.8,2.6c0,0-2.1-2.4-23.1-10.1c-20.1-7.3-21.9-12.3-22-12.8
|
||||
c0,0.6,0.3,9.6,19.6,19c-0.9-0.2-15.1-4.4-23.5-12.1c0,0,4.6,7.3,14.7,12.7l-14.7-1.1l9.4,4c0,0-16.1,0.7-31.8-4.5
|
||||
c0,0,4.6,3,7.8,4.7c0,0-20.4,1.5-28.5-0.2c1.8,0.5,16.5,4.4,21,5c0,0-18.4,1.3-28.7,6.9c0,0,2.3,19.5,14.4,41
|
||||
c-1.3-1.5-24.2-29.3-16.6-69.8c0,0-29-5-46.6,29.6s-19,77.1,10.7,99c-0.9-0.5-15-9.1-22.2-27.9C151.5,540.5,187,578,200,588.9
|
||||
c-58.5-45.5-37.5-116.9-32.2-132.2c-2.2-10.1-2.2-22.4,1.7-37.2c0,0-54.4,69.2-3.2,153.1c51.2,83.8,196.1,73.8,233.8-23.4
|
||||
C398.9,551.1,355.1,613.6,280,607.4z M212.6,385.6c-0.3,6.6,0.2,13.2,1.3,19.6c0.5,3.2,1,6.5,1.9,9.6l1.1,4.8l1.5,4.7
|
||||
c3.9,12.5,9.4,24.4,16.3,35.5c3.6,5.4,7,11,11.3,16c2.1,2.5,3.9,5.3,6.2,7.6c2.2,2.4,4.4,4.8,6.6,7.2c2.1,2.5,4.6,4.7,7,6.9
|
||||
l7.2,6.7c4.9,4.3,10.2,8.3,15.2,12.6c-5.5-3.7-10.9-7.5-16.2-11.4l-7.6-6.4c-2.5-2.2-5.1-4.2-7.4-6.7
|
||||
c-4.7-4.7-9.4-9.4-13.4-14.7c-4.4-5-8-10.6-11.7-16.1c-6.8-11.5-12.5-23.6-15.9-36.5C212.4,412.2,210.7,398.7,212.6,385.6z
|
||||
M203.3,401.5c0.2,4.4,0.4,8.8,0.9,13.1c0.4,4.4,0.8,8.7,1.4,13c1.2,8.6,2.6,17.3,4.5,25.8c1.8,8.5,4.2,16.9,6.9,25.2l2.1,6.2
|
||||
l2.4,6.1c1.4,4.2,3.6,8,5.2,12.1c-4.8-7.4-9-15.2-12.1-23.5c-3.3-8.2-5.9-16.7-7.8-25.4c-1.9-8.6-3.2-17.4-3.8-26.2
|
||||
C202.5,419.1,202.4,410.3,203.3,401.5z M192.9,468.3c-1.2-5.8-1.8-11.7-2.2-17.6c-0.3-5.9-0.3-11.9,0.1-17.7
|
||||
c0.4-5.9,1.3-11.8,2.8-17.5c-0.2,5.9-0.2,11.8-0.2,17.6c0.1,5.8,0.2,11.7,0.6,17.5c0.3,5.8,0.8,11.6,1.4,17.4l2,17.5
|
||||
C195.6,479.8,194,474.1,192.9,468.3z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g transform="translate(125.869582, 192.018739)">
|
||||
<g>
|
||||
<path d="M262.5,282c-0.3,0.5-0.6,1.2-0.9,1.8c-1.1,2-2.2,4.4-3,6.6l-14.1,39h-7.8l-8.3-22.8l-8.2,22.8h-7.8l-14.1-39
|
||||
c-1-2.8-2.5-6.1-3.9-8.4h9.5c0.1,2.2,1.2,5.5,2.2,8.3l12.8,35.5l8.2-22.7l-4.6-12.6c-1-2.8-2.6-6.1-3.9-8.4h9.5
|
||||
c0.1,2.2,1.1,5.5,2.1,8.3l12.9,35.5l12.8-35.5c1-2.8-0.3-5.7-1.8-8.3H262.5z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g transform="translate(159.727017, 192.018739)">
|
||||
<g>
|
||||
<path d="M268.2,290.5c0-3.2,0.3-6,1.1-8.4h-9.5c0.9,2.4,1.1,5.2,1.1,8.4c0,5.2,0,25.4,0,30.6c0,3.2-0.3,6-1.1,8.4h31.4l0.4-7.2
|
||||
H291c-0.5,1.3-2.7,4.7-8.3,4.7h-14.5V290.5z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g transform="translate(174.231269, 192.018739)">
|
||||
<g>
|
||||
<path d="M306.6,282h-18.8c0.9,2.4,1.1,5.2,1.1,8.4v30.6c0,3.2-0.2,6-1.1,8.4h18.8c13.1,0,24.9-8.2,24.9-23.7
|
||||
C331.5,290.2,319.7,282,306.6,282z M306.6,327h-10.4v-42.5h10.4c9,0,17.4,8.1,17.4,21.2C324,318.8,315.6,327,306.6,327z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g transform="translate(202.027605, 192.018739)">
|
||||
<g>
|
||||
<path d="M360.3,282h-18.8c0.9,2.4,1.1,5.2,1.1,8.4v30.6c0,3.2-0.3,6-1.1,8.4h18.8c13.1,0,24.8-8.2,24.8-23.7
|
||||
C385.2,290.2,373.4,282,360.3,282z M360.3,327H350v-42.5h10.4c9,0,17.4,8.1,17.4,21.2C377.7,318.8,369.3,327,360.3,327z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g transform="translate(220.56186, 192.018739)">
|
||||
<g>
|
||||
<path d="M407,321.1l-8.2-15.2c6.4-3.1,12.6-6.2,12.6-13.7c0-5.5-4.9-10.1-15.4-10.1h-18.7c0.9,2.4,1.1,5.2,1.1,8.4v30.6
|
||||
c0,3.2-0.3,6-1.1,8.4h9.5c-0.9-2.4-1.1-5.2-1.1-8.4v-1.3c0-5,2.9-8.1,6.6-10.5l7.8,14.6c1,1.8,1.7,3.6,2.2,5.6h10
|
||||
C410.8,327.4,408.5,323.8,407,321.1z M385.8,312.1v-27.9h3.8c7.6,0,14.4,1.7,14.6,7.5C404.6,301.5,391.1,303.2,385.8,312.1z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g transform="translate(236.122104, 192.018739)">
|
||||
<g>
|
||||
<path d="M447.4,321.1L433.3,282h-7.8l-14.1,39.1c-1,2.8-2.5,6-3.9,8.3h8.3c-2-3.4-2.6-6-1.8-8.3c1.1-3.1,2.3-5.6,5.2-7.3
|
||||
c4.4-2.6,11.2-2.5,15.6,0.2c2.6,1.6,3.8,4,4.9,7.3c1,2.7,2.1,6,2.1,8.2h9.6C450,327.1,448.4,323.9,447.4,321.1z M417.2,312.1
|
||||
l9.6-26.4l9.6,26.4C430.8,308.5,422.7,308.5,417.2,312.1z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g transform="translate(254.721007, 192.018739)">
|
||||
<g>
|
||||
<path d="M468,281.2c-13.7,0-24.7,10.9-24.7,24.5c0,13.7,10.9,24.7,24.7,24.7c5,0,9.7-1.5,13.8-4.2c3.1-2.2,6.3-1.3,7.1,2.6h0.6
|
||||
v-13.8c0-3.3,0.2-6.2,1.1-8.5h-9.9c1,2.3,1.3,5.2,1.3,8.5v6.2c-4,5.2-11.4,7.3-17.6,5.2c-7.5-2.7-13.5-10.5-13.5-20.6
|
||||
c0-13.2,9.7-22.1,19.8-21.6c9.3,0.5,16.2,7.5,18.4,15.7h0.8v-11c-1.3,0.1-3.4-0.9-4.8-2C479.4,282.9,474.9,281.2,468,281.2z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g transform="translate(274.462109, 192.018739)">
|
||||
<g>
|
||||
<path d="M506.1,281.2c-13.6,0-24.6,11-24.6,24.6c0,13.6,11,24.6,24.6,24.6c13.6,0,24.6-11,24.6-24.6
|
||||
C530.7,292.2,519.7,281.2,506.1,281.2z M516.8,325c-8.3,4.6-19.7-0.4-25.6-11.1c-5.9-10.6-3.9-22.9,4.3-27.5
|
||||
c8.2-4.5,19.7,0.5,25.5,11.1C526.9,308.2,525,320.6,516.8,325z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g transform="translate(294.892833, 192.018739)">
|
||||
<g>
|
||||
<path d="M552.3,282c3.9,2.2,4.7,7.3,4.7,11.3v25L530.1,282c-3,0-6.1,0-9.1,0l1.1,1.5v37.5c0,3.2-0.3,6-1.1,8.4h8.3
|
||||
c-3.8-2.2-4.7-7.3-4.7-11.3v-31.2l31.6,42.5h3.3v-39c0-3.2,0.3-6,1.1-8.4H552.3z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<path class="st0" d="M419,447.1c0,0,4.5-13.4-12.3-25.4c-16.2-11.6-7.1-24-6.5-24.8c-0.7,0.4-8.4,5.2-3.9,22.3
|
||||
c4.8,17.9,1.7,28.5,1.7,28.5s-8.4,0-17-11.5c0,0-0.6,14.3,11.5,17.6c12,3.4,15.1,15.1,7.8,15.9c-7.3,0.8-9.9-15.5-20.9-15.7
|
||||
c0,0,11.9,5.7,8,12.6c-4,6.9-9.2-5-9.2-5s0.1,7.9,6.3,12.5c0.9,0.7,2,1.3,3.1,1.8c1.2,0.5,2.6,0.9,4.2,1.2
|
||||
c3.3,0.5,6.5,4.3,8.7,10.2c3,8.2,4.1,20.4,1.2,34.2c-3.4,16.5-12.5,35.1-30.9,51.4c1-0.6,26.5-17,37.7-51.4
|
||||
c0.1-0.2,0.2-0.4,0.2-0.6c2.6-8,4.3-17,4.9-26.9c2.8-54.1,29.3-51.3,29.3-51.3S429.6,437.5,419,447.1z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 6.3 KiB |
Loading…
Reference in a new issue