- Full UI rewrite: dark tabbed layout (Exposure, Color Science, Color Correction, Lens, System) replacing cramped two-panel layout - Exposure tab: large pill controls for ISO/Shutter/ND/Gain/WB with ◀ ▶ nudge buttons, WB presets, AE mode row - Color Science tab (new): gamma curve selector, color gamut selector, quick presets (BRAW Film/Video/Ext.Video/Rec.709), video format (codec + frame rate) controls via /system/format - Color Correction tab: cleaner LGGO rows with per-channel LRGB labels, contrast and hue/sat/luma-contribution sliders - Lens tab: large vertical sliders for Focus/Iris/Zoom with AF button - System tab: connection, presets, manual API, footer links - BMDevice.js: added setColorScience(gamut, gamma) and setVideoFormat() - Always-visible top bar: recording pulse animation, transport controls, timecode, format display, camera switcher Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
558 lines
32 KiB
HTML
558 lines
32 KiB
HTML
<!DOCTYPE html>
|
|
<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>
|
|
|
|
<!-- Top Bar -->
|
|
<header id="topBar">
|
|
<nav id="camSwitcher">
|
|
<button class="camBtn selected" onclick="switchCamera(0)">CAM1</button>
|
|
<button class="camBtn" onclick="switchCamera(1)">CAM2</button>
|
|
<button class="camBtn" onclick="switchCamera(2)">CAM3</button>
|
|
<button class="camBtn" onclick="switchCamera(3)">CAM4</button>
|
|
<button class="camBtn" onclick="switchCamera(4)">CAM5</button>
|
|
<button class="camBtn" onclick="switchCamera(5)">CAM6</button>
|
|
<button class="camBtn" onclick="switchCamera(6)">CAM7</button>
|
|
<button class="camBtn" onclick="switchCamera(7)">CAM8</button>
|
|
</nav>
|
|
|
|
<div id="camInfo">
|
|
<span id="cameraName">NOT CONNECTED</span>
|
|
<span id="timecodeLabel" class="timecode">--:--:--:--</span>
|
|
</div>
|
|
|
|
<div id="formatDisplay">
|
|
<span id="formatCodec">—</span>
|
|
<span id="formatResolution">—</span>
|
|
<span id="formatFPS">—</span>
|
|
</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>
|
|
|
|
<button id="recordButton" onclick="cameras[ci].toggleRecord()" title="Toggle Record">
|
|
<span id="recDot"></span>
|
|
<span id="recLabel">REC</span>
|
|
</button>
|
|
</header>
|
|
|
|
<!-- 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>
|
|
|
|
<!-- ======== MAIN CONTENT ======== -->
|
|
<main id="mainContent">
|
|
|
|
<!-- ===== 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="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="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>
|
|
|
|
<!-- 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>
|
|
|
|
<!-- 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>
|
|
|
|
<!-- ===== 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="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="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="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>
|
|
<button class="ccApplyBtn" onclick="setCCFromUI(0)" title="Apply">➚</button>
|
|
<button class="ccResetBtn" onclick="resetCC(0)" title="Reset">⟳</button>
|
|
</div>
|
|
|
|
<!-- 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>
|
|
|
|
<!-- 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>
|
|
|
|
<!-- 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>
|