Projection mapping editable desde el navegador, sin herramientas externas: - web/stage/mapper.js (nuevo): compositor WebGL que texturiza el motor activo sobre superficies deformables (homografia por vertice: keystone correcto). - Editor con raton en el escenario (crear, arrastrar esquinas, mover, borrar) y previsualizacion arrastrable en el panel (raton/tactil) para editar desde el movil sin tocar la ventana de visuales. - Backend: estado "mapping" + evento set_mapping, persistido en data/mapping.json (ignorado en git). Seccion "Mapping" en el panel + texto de ayuda. - Solo motores web (butterchurn/hydra/shaders/mixer); projectM no se mapea. - .gitignore: excluye config de runtime (mapping.json, pm-favoritos.json). Incluye ademas trabajo en curso previo sin commitear (server.py, stage.js, panel.js/css, ayuda.json, hydra-sketches.json, problemas.md, start-projectm.sh), subido junto a peticion del autor. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
296 lines
12 KiB
HTML
296 lines
12 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="es">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>FOSFENO :: Panel</title>
|
|
<link rel="stylesheet" href="/panel/panel.css">
|
|
<link rel="stylesheet" href="/lib/codemirror/codemirror.css">
|
|
<link rel="stylesheet" href="/lib/codemirror/material-darker.css">
|
|
</head>
|
|
<body>
|
|
<header>
|
|
<h1>FOSFENO</h1>
|
|
<span id="conn" class="dot off" title="Conexion"></span>
|
|
</header>
|
|
|
|
<!-- Banda de avisos: aqui aparece cualquier error o aviso -->
|
|
<div id="notif" class="notif" hidden>
|
|
<span id="notif-msg"></span>
|
|
<button id="notif-close" aria-label="Cerrar aviso">×</button>
|
|
</div>
|
|
|
|
<!-- En movil las tarjetas van en una sola columna; en pantalla ancha,
|
|
en dos columnas (.column pasa a display:contents en movil). -->
|
|
<main>
|
|
<div class="column">
|
|
|
|
<!-- Encendido -->
|
|
<section class="card center" id="card-power">
|
|
<div class="cardhead">
|
|
<span class="label">Visuales</span>
|
|
<button class="info" data-help="power">i</button>
|
|
</div>
|
|
<button id="power" class="power-btn">ON</button>
|
|
</section>
|
|
|
|
<!-- Audio: tarjeta + BPM -->
|
|
<section class="card" id="card-audio">
|
|
<div class="cardhead">
|
|
<span class="label">Audio</span>
|
|
<button class="info" data-help="audio">i</button>
|
|
</div>
|
|
<div class="seg" id="audio-source">
|
|
<button id="audio-src-mic" class="segbtn" data-src="mic">Microfono (sala)</button>
|
|
<button id="audio-src-monitor" class="segbtn" data-src="monitor">Audio del navegador</button>
|
|
</div>
|
|
<select id="audio-device"><option>Detectando entradas...</option></select>
|
|
<button id="audio-apply" class="cmd accent">Aplicar entrada</button>
|
|
<button id="dev-rescan" class="cmd">Buscar dispositivos de nuevo</button>
|
|
<div class="row">
|
|
<span class="label">BPM detectado</span>
|
|
<span id="bpm" class="bpm">--</span>
|
|
</div>
|
|
<p class="hint">Con <b>Audio del navegador</b> las visuales reaccionan a
|
|
lo que suena en el equipo (Spotify, YouTube...) aunque lo oigas por los
|
|
cascos. Si conectas un microfono con el equipo ya encendido, pulsa
|
|
Buscar dispositivos de nuevo.</p>
|
|
</section>
|
|
|
|
<!-- Sensibilidad -->
|
|
<section class="card" id="card-sens">
|
|
<div class="cardhead">
|
|
<span class="label">Sensibilidad:
|
|
<span id="sens-val" class="value">1.0</span></span>
|
|
<button class="info" data-help="sensibilidad">i</button>
|
|
</div>
|
|
<input id="sens" type="range" min="0" max="4" step="0.1" value="1">
|
|
</section>
|
|
|
|
<!-- Estado: visual que se esta proyectando ahora mismo -->
|
|
<section class="card" id="card-now">
|
|
<span class="label">En pantalla</span>
|
|
<div id="now" class="now">-</div>
|
|
</section>
|
|
|
|
<!-- Sistema -->
|
|
<section class="card sys" id="card-sys">
|
|
<button id="reboot" class="sysbtn">Reiniciar</button>
|
|
<button id="shutdown" class="sysbtn danger">Apagar</button>
|
|
</section>
|
|
|
|
<p id="net-foot" class="netfoot">FOSFENO</p>
|
|
</div>
|
|
|
|
<div class="column">
|
|
|
|
<!-- Selector de motor -->
|
|
<section class="card" id="card-engines">
|
|
<div class="cardhead">
|
|
<span class="label">Motor de visuales</span>
|
|
<button class="info" data-help="engines">i</button>
|
|
</div>
|
|
<div class="engines">
|
|
<button class="engine" data-engine="projectm">
|
|
<strong>projectM</strong><small>nativo</small></button>
|
|
<button class="engine" data-engine="butterchurn">
|
|
<strong>Butter</strong><small>MilkDrop</small></button>
|
|
<button class="engine" data-engine="hydra">
|
|
<strong>Hydra</strong><small>codigo</small></button>
|
|
<button class="engine" data-engine="shaders">
|
|
<strong>Shaders</strong><small>GLSL</small></button>
|
|
<button class="engine" data-engine="mixer">
|
|
<strong>Mezcla</strong><small>camara</small></button>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Butterchurn -->
|
|
<section class="card" id="ctl-butterchurn" hidden>
|
|
<div class="cardhead">
|
|
<span class="label">Butterchurn</span>
|
|
<button class="info" data-help="butterchurn">i</button>
|
|
</div>
|
|
<div class="row">
|
|
<button class="cmd" data-action="prev">« Anterior</button>
|
|
<button class="cmd" data-action="next">Siguiente »</button>
|
|
</div>
|
|
<select id="bc-preset"><option>Cargando presets...</option></select>
|
|
<label class="check">
|
|
<input type="checkbox" id="bc-shuffle"> Cambio automatico de preset
|
|
</label>
|
|
<div class="seg">
|
|
<button id="bc-mode-seconds" class="segbtn">Por segundos</button>
|
|
<button id="bc-mode-beats" class="segbtn">Al compas (BPM)</button>
|
|
</div>
|
|
<div class="row">
|
|
<span class="label">Intervalo: <span id="bc-int-val">20</span>
|
|
<span id="bc-int-unit">s</span></span>
|
|
</div>
|
|
<input id="bc-interval" type="range" min="1" max="120" step="1" value="20">
|
|
<div class="row">
|
|
<span class="label">Transicion: <span id="bc-blend-val">2.7</span> s</span>
|
|
</div>
|
|
<input id="bc-blend" type="range" min="0" max="10" step="0.1" value="2.7">
|
|
</section>
|
|
|
|
<!-- Editor de codigo (Hydra / Shaders) -->
|
|
<section class="card" id="ctl-editor" hidden>
|
|
<div class="cardhead">
|
|
<span class="label" id="editor-title">Editor de codigo</span>
|
|
<button class="info" id="editor-info" data-help="hydra">i</button>
|
|
</div>
|
|
<select id="lib-select"><option>Libreria...</option></select>
|
|
<textarea id="code"></textarea>
|
|
<div class="row">
|
|
<button id="run-code" class="cmd accent">Ejecutar</button>
|
|
<button id="clear-code" class="cmd">Limpiar</button>
|
|
</div>
|
|
<p class="hint" id="editor-hint"></p>
|
|
</section>
|
|
|
|
<!-- Mezclador VJ -->
|
|
<section class="card" id="ctl-mixer" hidden>
|
|
<div class="cardhead">
|
|
<span class="label">Mezclador VJ</span>
|
|
<button class="info" data-help="mixer">i</button>
|
|
</div>
|
|
<div class="seg" id="mixer-source">
|
|
<button class="segbtn" data-src="cam">Camara</button>
|
|
<button class="segbtn" data-src="video">Video</button>
|
|
<button class="segbtn" data-src="mix">Mezcla</button>
|
|
</div>
|
|
<div class="row">
|
|
<span class="label">Fondo (capa de abajo)</span>
|
|
<select id="mix-fondo" class="inline">
|
|
<option value="cam">Camara</option>
|
|
<option value="butter">Visuales Butter (MilkDrop)</option>
|
|
</select>
|
|
</div>
|
|
<label class="check">
|
|
<input type="checkbox" id="mix-cam"> Camara activada
|
|
</label>
|
|
<select id="mix-camera"><option value="0">Camara por defecto</option></select>
|
|
<select id="mix-video"><option value="">-- sin video --</option></select>
|
|
<div class="row">
|
|
<button id="mix-rescan" class="cmd">Actualizar lista</button>
|
|
<button id="mix-upload-btn" class="cmd">Subir video o imagen</button>
|
|
<span id="mix-upload-status" class="hint"></span>
|
|
</div>
|
|
<input type="file" id="mix-upload" hidden
|
|
accept="video/*,image/jpeg,image/png,image/gif,image/webp">
|
|
<div class="row">
|
|
<span class="label">Modo de mezcla</span>
|
|
<select id="mix-blend" class="inline">
|
|
<option value="recorte">Recorte (personaje delante)</option>
|
|
<option value="blend">Fundido</option>
|
|
<option value="diff">Diferencia</option>
|
|
<option value="mult">Multiplicar</option>
|
|
<option value="add">Sumar</option>
|
|
<option value="layer">Capa</option>
|
|
</select>
|
|
</div>
|
|
<div id="mixer-sliders"></div>
|
|
<label class="check">
|
|
<input type="checkbox" id="mix-invert"> Invertir colores
|
|
</label>
|
|
<label class="check">
|
|
<input type="checkbox" id="mix-beat"> Pulso al ritmo
|
|
</label>
|
|
</section>
|
|
|
|
<!-- projectM -->
|
|
<section class="card" id="ctl-projectm" hidden>
|
|
<div class="cardhead">
|
|
<span class="label">projectM</span>
|
|
<button class="info" data-help="projectm">i</button>
|
|
</div>
|
|
<select id="pm-category">
|
|
<option value="">Todas las categorias</option>
|
|
</select>
|
|
<select id="pm-preset">
|
|
<option value="">-- rotando (elige uno para fijarlo) --</option>
|
|
</select>
|
|
<select id="pm-variante">
|
|
<option value="">-- variantes: rotando (elige una a dedo) --</option>
|
|
</select>
|
|
<div class="row">
|
|
<button class="cmd" data-action="prev">« Anterior</button>
|
|
<button class="cmd" data-action="next">Siguiente »</button>
|
|
</div>
|
|
<div class="row">
|
|
<button id="pm-lock" class="cmd">Congelar visual</button>
|
|
<button id="pm-fix" class="cmd">Fijar este estilo</button>
|
|
</div>
|
|
<p class="hint" id="pm-now">En pantalla: ...</p>
|
|
<div class="cardhead">
|
|
<span class="label">Favoritos (para pinchar en directo)</span>
|
|
</div>
|
|
<div class="row">
|
|
<button id="pm-fav-add" class="cmd accent">★ Guardar el de pantalla</button>
|
|
</div>
|
|
<div id="pm-fav-list"></div>
|
|
<label class="check">
|
|
<input type="checkbox" id="pm-shuffle"> Orden aleatorio
|
|
</label>
|
|
<div class="row">
|
|
<span class="label">Pantalla</span>
|
|
<select id="pm-monitor" class="inline">
|
|
<option value="auto">Auto (la del escenario)</option>
|
|
</select>
|
|
</div>
|
|
<div class="row">
|
|
<span class="label">Segundos por visual: <span id="pm-dur-val">60</span> s</span>
|
|
</div>
|
|
<input id="pm-duration" type="range" min="5" max="600" step="5" value="60">
|
|
<p class="hint">Congelar deja clavado el visual que se ve (al momento,
|
|
sin cortes). Fijar este estilo lo apunta en las listas y projectM
|
|
rota solo entre variantes de ese look. Cada cambio de listas o
|
|
deslizador relanza projectM (~1 s en negro).</p>
|
|
</section>
|
|
|
|
<!-- Mapping (projection mapping) -->
|
|
<section class="card" id="card-mapping">
|
|
<div class="cardhead">
|
|
<span class="label">Mapping</span>
|
|
<button class="info" data-help="mapping">i</button>
|
|
</div>
|
|
<label class="check">
|
|
<input type="checkbox" id="map-enabled"> Activar mapping
|
|
</label>
|
|
<label class="check">
|
|
<input type="checkbox" id="map-edit"> Modo edicion (arrastrar en el escenario)
|
|
</label>
|
|
<div class="row">
|
|
<button id="map-add" class="cmd accent">+ Anadir superficie</button>
|
|
<button id="map-reset" class="cmd">Reset</button>
|
|
</div>
|
|
<span class="label">Previsualizacion (arrastra las esquinas)</span>
|
|
<canvas id="map-preview"
|
|
style="width:100%;aspect-ratio:16/9;background:#0a0a0a;border:1px solid #333;border-radius:6px;display:block;margin:6px 0;touch-action:none;cursor:crosshair;"></canvas>
|
|
<div id="map-list"></div>
|
|
<p class="hint">1) Elige un motor que no sea projectM. 2) Pulsa
|
|
<b>Anadir superficie</b>. 3) <b>Arrastra las esquinas</b> aqui en la
|
|
previsualizacion (raton o dedo) para encajar la forma; se ve en el
|
|
proyector al instante. Cada superficie mapea la misma imagen. Se
|
|
guarda solo.</p>
|
|
</section>
|
|
|
|
</div>
|
|
</main>
|
|
|
|
<!-- Ventana de informacion -->
|
|
<div id="modal" class="modal" hidden>
|
|
<div class="modal-box">
|
|
<h2 id="modal-title">Informacion</h2>
|
|
<div id="modal-body"></div>
|
|
<button id="modal-close" class="cmd accent">Entendido</button>
|
|
</div>
|
|
</div>
|
|
|
|
<script src="/lib/socket.io.min.js"></script>
|
|
<script src="/lib/codemirror/codemirror.js"></script>
|
|
<script src="/lib/codemirror/javascript.js"></script>
|
|
<script src="/lib/codemirror/clike.js"></script>
|
|
<script src="/panel/panel.js"></script>
|
|
</body>
|
|
</html>
|