Compare commits

..

No commits in common. "ba66bd743a68e1c6fe740870b90af5aa2771a188" and "9c0a8765ce492d457a42a0a9f9a3e59ab5d691da" have entirely different histories.

8 changed files with 1273 additions and 1931 deletions

View file

@ -245,18 +245,6 @@ 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 */

View file

@ -1,22 +0,0 @@
# 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

View file

@ -22,7 +22,7 @@ If your camera does not have an ethernet port, use a USB-C to ethernet adapter.
![BM Camera Setup](screenshots/BMCameraSetup2.png)
> 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.
> 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.
## 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,9 +49,6 @@ 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.
@ -145,7 +142,6 @@ 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`
First made in 2024 by Dylan Speiser
Big thank you to all contributors!
(c) 2024 Dylan Speiser
<br>
Licensed under the GNU General Public License

View file

@ -1,552 +1,349 @@
<!-- (c) 2024 Dylan Speiser -->
<!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>
<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">
<!-- Background logo watermark -->
<div id="bgLogo" aria-hidden="true">
<img src="resources/wilddragon-logo.svg" alt="">
</div>
<!-- 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>
<!-- Top Bar -->
<header id="topBar">
<div id="camInfo">
<span id="cameraName">NOT CONNECTED</span>
<span id="timecodeLabel" class="timecode">--:--:--:--</span>
<!------ Page Content ------>
<!-- Header Div -->
<div class="flexContainerH" id="headerContainer">
<h1>Camera Control WebUI for Blackmagic Cameras</h1>
</div>
<div id="formatDisplay">
<span id="formatCodec"></span>
<span id="formatResolution"></span>
<span id="formatFPS"></span>
<!-- 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>
<div id="transportControls">
<button class="iconBtn" onclick="loopHandler('Loop')" title="Loop" id="loopButton">&#8635;</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">&#9204;</button>
<button class="iconBtn" onclick="cameras[ci].play()" title="Play">&#9654;</button>
<button class="iconBtn" onclick="cameras[ci].stop()" title="Stop">&#9209;</button>
<button class="iconBtn" onclick="cameras[ci].seek(true)" title="Next">&#9205;</button>
<!-- 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 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">&#10227</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">&#10138</button>
</div>
<span>Gamma</span>
<div class="flexContainerH" id="cameraControlColorCorrectionBottomContainer">
<button class="CCResetButton circleButton" onclick="resetCC(1)" title="Reset Gamma">&#10227</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">&#10138</button>
</div>
<span>Gain</span>
<div class="flexContainerH" id="cameraControlColorCorrectionBottomContainer">
<button class="CCResetButton circleButton" onclick="resetCC(2)" title="Reset Gain">&#10227</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">&#10138</button>
</div>
<span>Offset</span>
<div class="flexContainerH" id="cameraControlColorCorrectionBottomContainer">
<button class="CCResetButton circleButton" onclick="resetCC(3)" title="Reset Offset">&#10227</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">&#10138</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">&#9664</a>
<span id="ndFilterSpan" contenteditable="plaintext-only" onkeydown="NDFilterInputHandler()" onmousedown="NDFilterInputHandler()">0</span>
<a class="expAdjArr" href="#" onclick="increaseND()" id="NDR">&#9654</a>
</div>
</div>
<div class="ccExposureSettingContainer">
<span class="exposureControlLabel">GAIN</span>
<div class="ccExposureSettingValueContainer">
<a class="expAdjArr" href="#" onclick="decreaseGain()" id="GAL">&#9664</a>
<span id="gainSpan" contenteditable="plaintext-only" onkeydown="GainInputHandler()" onmousedown="GainInputHandler()">+0db</span>
<a class="expAdjArr" href="#" onclick="increaseGain()" id="GAR">&#9654</a>
</div>
</div>
<div class="ccExposureSettingContainer">
<span class="exposureControlLabel">SHUTTER</span>
<div class="ccExposureSettingValueContainer">
<a class="expAdjArr" href="#" onclick="decreaseShutter()" id="SHL">&#9664</a>
<span id="shutterSpan" contenteditable="plaintext-only" onkeydown="handleShutterInput()" onmousedown="handleShutterInput()">1/50</span>
<a class="expAdjArr" href="#" onclick="increaseShutter()" id="SHR">&#9654</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">&#9664</a>
<span id="whiteBalanceSpan" contenteditable="plaintext-only" onkeydown="WBInputHandler()" onmousedown="WBInputHandler()">5600K</span>
<a class="expAdjArr" href="#" onclick="increaseWhiteBalance()" id="WBR">&#9654</a>
</div>
<div class="ccExposureSettingValueContainer dNone" id="WBTintValueContainer">
<a class="expAdjArr" href="#" onclick="decreaseWhiteBalanceTint()" id="WBTL">&#9664</a>
<span id="whiteBalanceTintSpan" contenteditable="plaintext-only" onkeydown="WBTInputHandler()" onmousedown="WBTInputHandler()">0</span>
<a class="expAdjArr" href="#" onclick="increaseWhiteBalanceTint()" id="WBLR">&#9654</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>
</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>
</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">&#8635</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">&#9204</button>
<button class="circleButton" onclick="cameras[ci].seek(true)" title="Forward">&#9205</button>
<button class="circleButton" onclick="cameras[ci].toggleRecord()" title="Record" style="color: red;">&#9210</button>
<button class="circleButton" onclick="cameras[ci].play()" title="Play">&#9654</button>
<button class="circleButton" onclick="cameras[ci].stop()" title="Stop">&#9209</button>
</div>
<h2 id="timecodeLabel">TIMECODE</h2>
</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>
<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>
</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>
<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>
<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">&#10227</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">&#10227</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>
</div>
</div>
</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)">&#9664;</button>
<span id="ISODisplay" class="expValue" contenteditable="plaintext-only"
onkeydown="ISOKeyHandler(event)" onblur="ISOBlurHandler()">—</span>
<button class="adjBtn" onclick="adjustISO(100)">&#9654;</button>
</div>
</div>
<div class="expPill">
<span class="expPillLabel">SHUTTER</span>
<div class="expPillValue">
<button class="adjBtn" onclick="decreaseShutter()">&#9664;</button>
<span id="shutterDisplay" class="expValue" contenteditable="plaintext-only"
onkeydown="handleShutterInput()" onmousedown="handleShutterInput()">—</span>
<button class="adjBtn" onclick="increaseShutter()">&#9654;</button>
</div>
</div>
<div class="expPill">
<span class="expPillLabel">ND FILTER</span>
<div class="expPillValue">
<button class="adjBtn" onclick="decreaseND()">&#9664;</button>
<span id="ndFilterDisplay" class="expValue" contenteditable="plaintext-only"
onkeydown="NDFilterInputHandler()" onmousedown="NDFilterInputHandler()">—</span>
<button class="adjBtn" onclick="increaseND()">&#9654;</button>
</div>
</div>
<div class="expPill">
<span class="expPillLabel">GAIN</span>
<div class="expPillValue">
<button class="adjBtn" onclick="decreaseGain()">&#9664;</button>
<span id="gainDisplay" class="expValue" contenteditable="plaintext-only"
onkeydown="GainInputHandler()" onmousedown="GainInputHandler()">—</span>
<button class="adjBtn" onclick="increaseGain()">&#9654;</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 &#8597;</span>
<div class="expPillValue" id="WBValueContainer">
<button class="adjBtn" onclick="decreaseWhiteBalance()">&#9664;</button>
<span id="whiteBalanceDisplay" class="expValue" contenteditable="plaintext-only"
onkeydown="WBInputHandler()" onmousedown="WBInputHandler()">—</span>
<button class="adjBtn" onclick="increaseWhiteBalance()">&#9654;</button>
</div>
<div class="expPillValue hidden" id="WBTintValueContainer">
<button class="adjBtn" onclick="decreaseWhiteBalanceTint()">&#9664;</button>
<span id="whiteBalanceTintDisplay" class="expValue" contenteditable="plaintext-only"
onkeydown="WBTInputHandler()" onmousedown="WBTInputHandler()">—</span>
<button class="adjBtn" onclick="increaseWhiteBalanceTint()">&#9654;</button>
</div>
<button class="awbBtn" onclick="cameras[ci].doAutoWhitebalance()" title="Auto White Balance">AWB</button>
</div>
<!-- Footer Div -->
<div class="flexContainerH" id="footerContainer">
<div id="footerLeft">
<span class="">(v 1.3)</span>
<span id="activeElementSpan"></span>
</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 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>
</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">&#10138;</button>
<button class="ccResetBtn" onclick="resetCC(0)" title="Reset">&#10227;</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">&#10138;</button>
<button class="ccResetBtn" onclick="resetCC(1)" title="Reset">&#10227;</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">&#10138;</button>
<button class="ccResetBtn" onclick="resetCC(2)" title="Reset">&#10227;</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">&#10138;</button>
<button class="ccResetBtn" onclick="resetCC(3)" title="Reset">&#10227;</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">&#10227;</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">&#10227;</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>
</div>
</body>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 91 KiB

View file

@ -1,120 +0,0 @@
<?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>

Before

Width:  |  Height:  |  Size: 6.3 KiB

1156
style.css

File diff suppressed because it is too large Load diff

1007
web-ui.js

File diff suppressed because it is too large Load diff