371 líneas
22 KiB
HTML
371 líneas
22 KiB
HTML
<!doctype html>
|
||
<html lang="es">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<title>Labmagic</title>
|
||
<link rel="icon" href="/icon.png">
|
||
<style>
|
||
:root {
|
||
--bg: #0d0d0d; --hud: #000; --card: #181818; --border: #2a2a2a; --btn: #2b2b2b; --btn-hover: #3c3c3c;
|
||
--trough: #303030; --knob: #ececec; --fg: #f3f3f3; --muted: #9b9b9b; --dim: #555; --rec: #e3262c;
|
||
--on: #3ad66c; --busy: #f0a500; --off: #4a4a4a; --sheet: #161616;
|
||
}
|
||
* { box-sizing: border-box; -webkit-user-select: none; user-select: none; }
|
||
html, body { margin: 0; height: 100%; background: var(--bg); color: var(--fg);
|
||
font: 13px "Segoe UI", system-ui, sans-serif; overflow-x: hidden; }
|
||
button { font: inherit; color: var(--fg); background: var(--btn); border: 1px solid transparent; border-radius: 6px;
|
||
padding: 7px 10px; cursor: pointer; }
|
||
button:hover { background: var(--btn-hover); }
|
||
button:active { background: #555; }
|
||
button:disabled { opacity: .45; cursor: default; }
|
||
button.on { border-color: var(--rec); background: #2a1416; }
|
||
button.big { font-size: 16px; font-weight: 600; padding: 12px 10px; letter-spacing: .5px; }
|
||
button.sq { padding: 7px 0; width: 30px; }
|
||
|
||
/* HUD */
|
||
.hud { background: var(--hud); padding: 7px 10px 6px; }
|
||
.top { display: flex; align-items: center; gap: 8px; }
|
||
.led { width: 11px; height: 11px; border-radius: 50%; background: var(--off); flex: none; }
|
||
.led.on { background: var(--on); box-shadow: 0 0 6px var(--on); }
|
||
.led.busy { background: var(--busy); }
|
||
.name { font-weight: 600; font-size: 14px; cursor: pointer; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||
.name:hover { text-decoration: underline; }
|
||
.tc { margin-left: auto; font: 600 22px "Consolas", "Segoe UI", monospace; letter-spacing: 1px; white-space: nowrap; }
|
||
.tc.rec { color: var(--rec); }
|
||
.dot { color: transparent; font-size: 12px; width: 10px; }
|
||
.dot.rec { color: var(--rec); animation: blink 1s steps(1) infinite; }
|
||
@keyframes blink { 50% { color: transparent; } }
|
||
.status { color: var(--muted); font-size: 11px; margin-top: 1px; display: flex; gap: 8px; }
|
||
.status .pw { margin-left: auto; }
|
||
.cells { display: grid; grid-template-columns: repeat(6, 1fr); gap: 3px; margin-top: 6px; }
|
||
@media (max-width: 330px) { .cells { grid-template-columns: repeat(3, 1fr); } }
|
||
.cell { background: #0a0a0a; border: 1px solid #1c1c1c; border-radius: 6px; padding: 4px 2px 5px; text-align: center; }
|
||
.cell .l { color: var(--muted); font-size: 9px; letter-spacing: .8px; }
|
||
.cell .v { font: 600 15px "Segoe UI", sans-serif; margin-top: 1px; white-space: nowrap; overflow: hidden; }
|
||
.cell.click { cursor: pointer; }
|
||
.cell.click .v { border-bottom: 1px solid #3a3a3a; display: inline-block; padding: 0 2px; }
|
||
.cell.click:hover { background: #151515; }
|
||
.cell.click:hover .v { border-bottom-color: var(--fg); }
|
||
|
||
.banner { display: none; padding: 6px 10px; font-size: 12px; background: var(--rec); }
|
||
.banner.warn { background: #8a5a00; }
|
||
.banner.ok { background: #1f4d2b; }
|
||
.banner.show { display: block; }
|
||
|
||
main { padding: 8px 10px 10px; display: flex; flex-direction: column; gap: 8px; }
|
||
.row { display: flex; gap: 6px; align-items: stretch; }
|
||
.row > .grow { flex: 1; }
|
||
.tog { font-size: 11.5px; padding: 6px 8px; flex: 1; white-space: nowrap; }
|
||
.swatch { display: inline-block; width: 10px; height: 10px; border-radius: 50%; vertical-align: -1px; margin-right: 4px;
|
||
border: 1px solid #666; }
|
||
|
||
.srow { display: grid; grid-template-columns: 44px 30px 1fr 30px; gap: 5px; align-items: center; }
|
||
.srow .lab { font-size: 12px; color: var(--muted); }
|
||
.srow .lab b { display: block; color: var(--fg); font-weight: 600; font-size: 12px; white-space: nowrap; }
|
||
input[type=range] { -webkit-appearance: none; width: 100%; height: 28px; background: transparent; margin: 0; cursor: pointer; }
|
||
input[type=range]:disabled { opacity: .4; cursor: default; }
|
||
input[type=range]::-webkit-slider-runnable-track { height: 6px; background: var(--trough); border-radius: 3px; }
|
||
input[type=range]::-webkit-slider-thumb { -webkit-appearance: none; width: 18px; height: 18px; border-radius: 50%;
|
||
background: var(--knob); margin-top: -6px; box-shadow: 0 1px 3px #000; }
|
||
.rec-row { display: flex; align-items: center; gap: 12px; background: var(--card); border-radius: 8px; padding: 8px 10px; }
|
||
.recbtn { width: 46px; height: 46px; border-radius: 50%; background: #1a1a1a; border: 3px solid #444; position: relative;
|
||
flex: none; padding: 0; }
|
||
.recbtn::after { content: ""; position: absolute; inset: 7px; border-radius: 50%; background: var(--rec); transition: inset .15s, border-radius .15s; }
|
||
.recbtn:hover { border-color: #777; }
|
||
.recbtn.rec::after { inset: 12px; border-radius: 4px; }
|
||
.recinfo .s { font-weight: 700; letter-spacing: 1px; }
|
||
.recinfo .s.rec { color: var(--rec); }
|
||
.recinfo .i { color: var(--muted); font-size: 11px; margin-top: 2px; }
|
||
.foot { display: flex; gap: 8px; color: var(--dim); font-size: 10.5px; align-items: center; }
|
||
.foot a { color: var(--muted); cursor: pointer; margin-left: auto; white-space: nowrap; }
|
||
.foot a:hover { color: var(--fg); }
|
||
|
||
/* Selector estilo cámara (hoja inferior) */
|
||
.veil { position: fixed; inset: 0; background: rgba(0,0,0,.55); display: none; }
|
||
.veil.show { display: block; }
|
||
.sheet { position: fixed; left: 0; right: 0; bottom: 0; background: var(--sheet); border-top: 1px solid var(--border);
|
||
border-radius: 12px 12px 0 0; padding: 10px 12px 12px; transform: translateY(100%); transition: transform .18s ease-out;
|
||
max-height: 85%; overflow-y: auto; }
|
||
.sheet.show { transform: none; }
|
||
.sh-head { display: flex; align-items: baseline; gap: 10px; margin-bottom: 8px; }
|
||
.sh-head .t { color: var(--muted); font-size: 11px; letter-spacing: 1px; }
|
||
.sh-head .cur { font: 600 20px "Segoe UI", sans-serif; }
|
||
.sh-head .x { margin-left: auto; color: var(--muted); cursor: pointer; padding: 0 4px; font-size: 16px; }
|
||
.sh-head .x:hover { color: var(--fg); }
|
||
.chips { display: grid; grid-template-columns: repeat(auto-fill, minmax(54px, 1fr)); gap: 4px; margin-bottom: 6px; }
|
||
.chip { background: #222; border: 1px solid transparent; border-radius: 6px; padding: 7px 2px; text-align: center;
|
||
font-weight: 600; cursor: pointer; font-size: 13px; white-space: nowrap; }
|
||
.chip:hover { background: #333; }
|
||
.chip.dim { color: var(--muted); font-weight: 400; background: #1c1c1c; }
|
||
.chip.sel { background: var(--fg); color: #000; }
|
||
.chip.wide { grid-column: span 2; }
|
||
.sub { color: var(--muted); font-size: 10.5px; letter-spacing: .8px; margin: 6px 0 3px; }
|
||
.note { color: var(--dim); font-size: 10.5px; margin-top: 4px; }
|
||
.kv { display: grid; grid-template-columns: 36px 1fr 36px; gap: 6px; align-items: center; font-size: 10.5px; color: var(--muted); }
|
||
.ticks { display: flex; justify-content: space-between; padding: 0 42px; color: var(--dim); font-size: 9px; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<header class="hud">
|
||
<div class="top">
|
||
<span class="led" id="led"></span>
|
||
<span class="name" id="name" title="Pulsa para conectar o desconectar">Sin cámara</span>
|
||
<span class="tc" id="tc">00:00:00:00</span><span class="dot" id="dot">●</span>
|
||
</div>
|
||
<div class="status"><span id="status">Buscando Labmagic…</span><span class="pw" id="power"></span></div>
|
||
<div class="cells">
|
||
<div class="cell"><div class="l">FPS</div><div class="v" id="c_fps">—</div></div>
|
||
<div class="cell click" data-pick="shutter"><div class="l">SHUTTER</div><div class="v" id="c_sh">—</div></div>
|
||
<div class="cell click" data-pick="iris"><div class="l">IRIS</div><div class="v" id="c_iris">—</div></div>
|
||
<div class="cell click" data-pick="iso"><div class="l">ISO</div><div class="v" id="c_iso">—</div></div>
|
||
<div class="cell click" data-pick="wb"><div class="l">WB</div><div class="v" id="c_wb">—</div></div>
|
||
<div class="cell click" data-pick="wb"><div class="l">TINT</div><div class="v" id="c_tint">—</div></div>
|
||
</div>
|
||
</header>
|
||
<div class="banner" id="banner"></div>
|
||
<main>
|
||
<div class="row">
|
||
<button class="big grow" id="af" title="Autofoco (también con la barra espaciadora)">AUTOFOCO (AF)</button>
|
||
<button class="tog" id="peak" style="flex:0 0 auto" title="Focus assist con líneas de color en la salida elegida en Labmagic"><span class="swatch" id="peaksw"></span>PEAK</button>
|
||
</div>
|
||
<div class="row">
|
||
<button class="tog" id="zebra" title="Zebra en la salida elegida">ZEBRA</button>
|
||
<button class="tog" id="false" title="Falso color en la salida elegida">FALSO COLOR</button>
|
||
<button class="tog" id="afauto" title="Vuelve a enfocar cada pocos segundos (intervalo en Labmagic → Ajustes)">AF AUTO</button>
|
||
</div>
|
||
<div class="srow">
|
||
<div class="lab">Foco<b id="focus_txt">—</b></div>
|
||
<button class="sq" id="f_minus" title="Más cerca (Mayús: paso grande)">◀</button>
|
||
<input type="range" id="focus" min="0" max="1000" value="500" disabled>
|
||
<button class="sq" id="f_plus" title="Más lejos (Mayús: paso grande)">▶</button>
|
||
</div>
|
||
<div class="srow">
|
||
<div class="lab">Iris<b id="iris_txt">—</b></div>
|
||
<button class="sq" id="i_minus" title="Abrir">◀</button>
|
||
<input type="range" id="iris" min="0" max="1000" value="0" disabled>
|
||
<button class="sq" id="i_plus" title="Cerrar">▶</button>
|
||
</div>
|
||
<div class="rec-row">
|
||
<button class="recbtn" id="rec" title="Grabar / parar"></button>
|
||
<div class="recinfo"><div class="s" id="recstate">GRABAR</div><div class="i" id="recinfo">—</div></div>
|
||
</div>
|
||
<div class="foot"><span id="lens"></span><a id="open" title="Trae la ventana de Labmagic al frente">abrir Labmagic ⇱</a></div>
|
||
</main>
|
||
<div class="veil" id="veil"></div>
|
||
<div class="sheet" id="sheet"></div>
|
||
|
||
<script>
|
||
(() => {
|
||
const $ = id => document.getElementById(id);
|
||
const ISO_FULL = [100, 200, 400, 800, 1600, 3200, 6400, 12800, 25600];
|
||
const ISO_ALL = [100,125,160,200,250,320,400,500,640,800,1000,1250,1600,2000,2500,3200,4000,5000,6400,8000,10000,12800,16000,20000,25600];
|
||
const ANG_MAIN = [45, 90, 172.8, 180, 270, 360];
|
||
const ANG_ALL = [11.2,15,22.5,30,37.5,45,60,72,90,108,120,144,150,172.8,180,216,270,360];
|
||
const SPEEDS = [24,25,30,48,50,60,100,120,125,200,250,500,1000,2000];
|
||
const FSTOPS = [1.4,1.8,2.0,2.8,3.5,4.0,4.5,5.6,6.3,8.0,11,16,22];
|
||
const WB_CHIPS = [["☀ Día",5600,10],["💡 Tungst.",3200,0],["▭ Fluor.",4000,15],["☁ Nublado",6500,10],["⌂ Sombra",7500,10]];
|
||
const PEAK_COL = ["#e3262c","#3ad66c","#3b82f6","#f3f3f3","#000"];
|
||
const PEAK_NAME = ["Rojo","Verde","Azul","Blanco","Negro"];
|
||
|
||
let S = {}; // último estado recibido
|
||
let dragging = null; // deslizador que se está arrastrando ("focus" | "iris" | "wb" | "tint")
|
||
let bannerT = null;
|
||
let alive = false;
|
||
|
||
const cmd = (c, extra = {}) =>
|
||
fetch("/cmd", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ cmd: c, ...extra }) })
|
||
.catch(() => {});
|
||
|
||
// Envío con límite de ritmo para los deslizadores
|
||
const pending = {};
|
||
let flushT = null;
|
||
function throttled(key, fn) {
|
||
pending[key] = fn;
|
||
if (!flushT) flushT = setTimeout(() => { flushT = null; const p = { ...pending }; for (const k in pending) delete pending[k]; Object.values(p).forEach(f => f()); }, 120);
|
||
}
|
||
|
||
function banner(text, level = "error", secs = 6) {
|
||
const b = $("banner");
|
||
b.textContent = text; b.className = "banner show " + level;
|
||
clearTimeout(bannerT);
|
||
bannerT = setTimeout(() => b.className = "banner", secs * 1000);
|
||
}
|
||
|
||
function render(s) {
|
||
S = s;
|
||
const on = !!s.connected;
|
||
$("led").className = "led " + (on ? "on" : (s.busy ? "busy" : ""));
|
||
$("name").textContent = s.name || "Sin cámara";
|
||
$("status").textContent = s.status || "";
|
||
$("power").textContent = s.power || "";
|
||
$("tc").textContent = s.tc || "00:00:00:00";
|
||
$("tc").className = "tc" + (s.rec ? " rec" : "");
|
||
$("dot").className = "dot" + (s.rec ? " rec" : "");
|
||
$("c_fps").textContent = s.fps || "—";
|
||
$("c_sh").textContent = s.shutter || "—";
|
||
$("c_iris").textContent = s.iris || "—";
|
||
$("c_iso").textContent = s.iso || "—";
|
||
$("c_wb").textContent = s.wb ? s.wb + "K" : "—";
|
||
$("c_tint").textContent = (s.tint === 0 || s.tint) ? (s.tint > 0 ? "+" + s.tint : String(s.tint)) : "—";
|
||
$("peak").classList.toggle("on", !!s.peak);
|
||
$("peaksw").style.background = PEAK_COL[s.peak_colour || 0];
|
||
$("zebra").classList.toggle("on", !!s.zebra);
|
||
$("false").classList.toggle("on", !!s.false);
|
||
$("afauto").classList.toggle("on", !!s.af_auto);
|
||
for (const id of ["af","peak","zebra","false","afauto","f_minus","f_plus","i_minus","i_plus","rec"]) $(id).disabled = !on;
|
||
$("focus").disabled = !on; $("iris").disabled = !on;
|
||
if (dragging !== "focus") { if (s.focus !== null && s.focus !== undefined) $("focus").value = Math.round(s.focus * 1000); }
|
||
if (dragging !== "iris") { if (s.aperture !== null && s.aperture !== undefined) $("iris").value = Math.round(s.aperture * 1000); }
|
||
$("focus_txt").textContent = s.focus_text || "—";
|
||
$("iris_txt").textContent = s.iris || "—";
|
||
$("rec").classList.toggle("rec", !!s.rec);
|
||
$("recstate").textContent = s.rec ? "GRABANDO" : "GRABAR";
|
||
$("recstate").className = "s" + (s.rec ? " rec" : "");
|
||
$("recinfo").textContent = s.rec_info || (on ? "" : "—");
|
||
$("lens").textContent = s.lens || "";
|
||
if (s.notice && s.notice.t !== (render.lastNotice || 0)) { render.lastNotice = s.notice.t; banner(s.notice.text, s.notice.level, s.notice.secs || 6); }
|
||
if (sheetKind) refreshSheet();
|
||
}
|
||
|
||
// --- conexión con Labmagic (SSE con reintento)
|
||
function listen() {
|
||
const es = new EventSource("/events");
|
||
es.onopen = () => { alive = true; };
|
||
es.onmessage = e => { try { render(JSON.parse(e.data)); } catch (_) {} };
|
||
es.onerror = () => {
|
||
es.close(); alive = false;
|
||
$("led").className = "led"; $("status").textContent = "Labmagic no está abierta: ábrela y este panel se conecta solo";
|
||
setTimeout(listen, 2000);
|
||
};
|
||
}
|
||
listen();
|
||
|
||
// --- botones
|
||
$("name").onclick = () => cmd("connect");
|
||
$("af").onclick = () => { cmd("af"); const b = $("af"); b.textContent = "AF ● enviado"; setTimeout(() => b.innerHTML = "AUTOFOCO (AF)", 900); };
|
||
$("peak").onclick = () => cmd("peak", { on: !S.peak });
|
||
$("peak").oncontextmenu = e => { e.preventDefault(); openSheet("peak"); };
|
||
$("zebra").onclick = () => cmd("zebra", { on: !S.zebra });
|
||
$("false").onclick = () => cmd("false", { on: !S.false });
|
||
$("afauto").onclick = () => cmd("af_auto", { on: !S.af_auto });
|
||
$("rec").onclick = () => cmd("record");
|
||
$("open").onclick = () => cmd("show");
|
||
const step = e => (e.shiftKey ? 0.05 : 0.01);
|
||
$("f_minus").onclick = e => cmd("focus_delta", { d: -step(e) });
|
||
$("f_plus").onclick = e => cmd("focus_delta", { d: step(e) });
|
||
$("i_minus").onclick = e => cmd("iris_delta", { d: -0.05 });
|
||
$("i_plus").onclick = e => cmd("iris_delta", { d: 0.05 });
|
||
for (const [id, key, c] of [["focus", "focus", "focus"], ["iris", "iris", "iris"]]) {
|
||
const el = $(id);
|
||
el.oninput = () => { dragging = key; const v = el.value / 1000; if (key === "focus") $("focus_txt").textContent = v.toFixed(2); throttled(c, () => cmd(c, { v })); };
|
||
el.onchange = () => { const v = el.value / 1000; cmd(c, { v }); setTimeout(() => dragging = null, 300); };
|
||
}
|
||
// Teclado: espacio = AF, flechas = foco (cuando el panel tiene el foco)
|
||
document.addEventListener("keydown", e => {
|
||
if (!S.connected) return;
|
||
if (e.code === "Space") { e.preventDefault(); $("af").click(); }
|
||
else if (e.code === "ArrowLeft") { e.preventDefault(); cmd("focus_delta", { d: -step(e) }); }
|
||
else if (e.code === "ArrowRight") { e.preventDefault(); cmd("focus_delta", { d: step(e) }); }
|
||
});
|
||
|
||
// --- selectores (hoja inferior)
|
||
let sheetKind = null;
|
||
const wbState = { k: 5600, t: 0 };
|
||
document.querySelectorAll(".cell.click").forEach(c => c.onclick = () => openSheet(c.dataset.pick));
|
||
$("veil").onclick = closeSheet;
|
||
function closeSheet() { sheetKind = null; $("sheet").classList.remove("show"); $("veil").classList.remove("show"); }
|
||
function openSheet(kind) {
|
||
if (!S.connected) { banner("Conecta la cámara para cambiar valores", "warn", 3); return; }
|
||
sheetKind = kind;
|
||
if (kind === "wb") { wbState.k = S.wb || 5600; wbState.t = S.tint || 0; }
|
||
buildSheet(kind);
|
||
$("sheet").classList.add("show"); $("veil").classList.add("show");
|
||
}
|
||
const h = (tag, cls, text) => { const e = document.createElement(tag); if (cls) e.className = cls; if (text !== undefined) e.textContent = text; return e; };
|
||
function chips(parent, items, cur, onpick, dim) {
|
||
const g = h("div", "chips");
|
||
for (const [label, val] of items) {
|
||
const c = h("div", "chip" + (dim && dim.has(val) ? " dim" : "") + (cur !== null && cur !== undefined && Math.abs(cur - val) < 1e-6 ? " sel" : ""), label);
|
||
c.onclick = () => onpick(val);
|
||
g.appendChild(c);
|
||
}
|
||
parent.appendChild(g);
|
||
return g;
|
||
}
|
||
function head(parent, title, cur) {
|
||
const hd = h("div", "sh-head");
|
||
hd.appendChild(h("span", "t", title)); const cv = h("span", "cur", cur); hd.appendChild(cv);
|
||
const x = h("span", "x", "✕"); x.onclick = closeSheet; hd.appendChild(x);
|
||
parent.appendChild(hd);
|
||
return cv;
|
||
}
|
||
function refreshSheet() { if (sheetKind && sheetKind !== "wb") buildSheet(sheetKind); }
|
||
function buildSheet(kind) {
|
||
const sh = $("sheet"); sh.innerHTML = "";
|
||
if (kind === "iso") {
|
||
const cur = parseInt(S.iso) || null;
|
||
head(sh, "ISO", S.iso || "—");
|
||
const pick = v => { cmd("iso", { v }); closeSheet(); };
|
||
chips(sh, ISO_FULL.map(v => [String(v), v]), cur, pick);
|
||
chips(sh, ISO_ALL.filter(v => !ISO_FULL.includes(v)).map(v => [String(v), v]), cur, pick, new Set(ISO_ALL));
|
||
sh.appendChild(h("div", "note", "Nativos de la Pocket 4K: 400 y 3200 · tercios en gris"));
|
||
} else if (kind === "shutter") {
|
||
head(sh, "OBTURADOR", S.shutter || "—");
|
||
const curA = S.angle, curS = S.speed;
|
||
sh.appendChild(h("div", "sub", "ÁNGULO"));
|
||
const pa = a => { cmd("angle", { a }); closeSheet(); };
|
||
chips(sh, ANG_MAIN.map(a => [a + "°", a]), curA, pa);
|
||
chips(sh, ANG_ALL.filter(a => !ANG_MAIN.includes(a)).map(a => [a + "°", a]), curA, pa, new Set(ANG_ALL));
|
||
sh.appendChild(h("div", "sub", "VELOCIDAD 1/x"));
|
||
chips(sh, SPEEDS.map(s => ["1/" + s, s]), curS, s => { cmd("speed", { s }); closeSheet(); });
|
||
} else if (kind === "iris") {
|
||
head(sh, "IRIS", S.iris || "—");
|
||
chips(sh, FSTOPS.map(f => ["f/" + f, f]), null, f => { cmd("iris_f", { f }); closeSheet(); });
|
||
const kv = h("div", "kv"); kv.appendChild(h("span", "", "abierto"));
|
||
const r = h("input"); r.type = "range"; r.min = 0; r.max = 1000; r.value = Math.round((S.aperture || 0) * 1000);
|
||
r.oninput = () => { dragging = "iris"; throttled("iris", () => cmd("iris", { v: r.value / 1000 })); };
|
||
r.onchange = () => { cmd("iris", { v: r.value / 1000 }); setTimeout(() => dragging = null, 300); };
|
||
kv.appendChild(r); kv.appendChild(h("span", "", "cerrado")); sh.appendChild(kv);
|
||
const g = h("div", "chips"); const a = h("div", "chip", "AUTO IRIS"); a.onclick = () => { cmd("auto_iris"); closeSheet(); }; g.appendChild(a); sh.appendChild(g);
|
||
} else if (kind === "wb") {
|
||
const cv = head(sh, "BALANCE DE BLANCOS", "");
|
||
const refresh = () => cv.textContent = `${wbState.k}K ${wbState.t >= 0 ? "+" : ""}${wbState.t}`;
|
||
const send = () => throttled("wb", () => cmd("wb", { k: wbState.k, t: wbState.t }));
|
||
refresh();
|
||
const kv = h("div", "kv"); kv.appendChild(h("span", "", "2500"));
|
||
const ks = h("input"); ks.type = "range"; ks.min = 2500; ks.max = 10000; ks.step = 50; ks.value = wbState.k;
|
||
ks.oninput = () => { wbState.k = +ks.value; refresh(); send(); markPreset(); };
|
||
kv.appendChild(ks); kv.appendChild(h("span", "", "10000")); sh.appendChild(kv);
|
||
const ticks = h("div", "ticks"); for (const k of [3200, 4000, 5600, 6500, 7500]) ticks.appendChild(h("span", "", String(k))); sh.appendChild(ticks);
|
||
const g = h("div", "chips"); g.style.gridTemplateColumns = "repeat(3, 1fr)";
|
||
const presetChips = [];
|
||
for (const [label, k, t] of WB_CHIPS) {
|
||
const c = h("div", "chip", label); c.dataset.k = k;
|
||
c.onclick = () => { wbState.k = k; wbState.t = t; ks.value = k; ts.value = t; refresh(); send(); markPreset(); };
|
||
g.appendChild(c); presetChips.push(c);
|
||
}
|
||
const awb = h("div", "chip", "AUTO WB"); awb.onclick = () => { cmd("awb"); closeSheet(); }; g.appendChild(awb);
|
||
sh.appendChild(g);
|
||
const markPreset = () => presetChips.forEach(c => c.classList.toggle("sel", +c.dataset.k === wbState.k));
|
||
const tr = h("div", "kv"); tr.style.gridTemplateColumns = "36px 1fr 30px 30px";
|
||
tr.appendChild(h("span", "", "Tinte"));
|
||
const ts = h("input"); ts.type = "range"; ts.min = -50; ts.max = 50; ts.value = wbState.t;
|
||
ts.oninput = () => { wbState.t = +ts.value; refresh(); send(); };
|
||
tr.appendChild(ts);
|
||
for (const [txt, d] of [["−", -1], ["+", 1]]) { const b = h("button", "sq", txt); b.onclick = () => { wbState.t = Math.max(-50, Math.min(50, wbState.t + d)); ts.value = wbState.t; refresh(); send(); }; tr.appendChild(b); }
|
||
sh.appendChild(tr);
|
||
markPreset();
|
||
} else if (kind === "peak") {
|
||
head(sh, "COLOR DEL PEAKING", PEAK_NAME[S.peak_colour || 0]);
|
||
const g = h("div", "chips");
|
||
PEAK_NAME.forEach((n, i) => { const c = h("div", "chip" + (i === (S.peak_colour || 0) ? " sel" : "")); c.innerHTML = `<span class="swatch" style="background:${PEAK_COL[i]}"></span>${n}`; c.onclick = () => { cmd("peak_colour", { c: i }); closeSheet(); }; g.appendChild(c); });
|
||
sh.appendChild(g);
|
||
sh.appendChild(h("div", "note", "Clic derecho en PEAK abre este selector"));
|
||
}
|
||
}
|
||
})();
|
||
</script>
|
||
</body>
|
||
</html>
|