MOTORES: pastillas configurables y destino (salida o capa)

Las pestanas de capa de la barra superior no valian: mezclaban navegar por el
panel con elegir sobre que se trabaja, y sacaban del panel de directo. Se
quitan y todo pasa a MOTORES, con dos decisiones separadas:

  DONDE  -> fila 'Donde se ve': SALIDA o una capa del mapping (+ crea una).
  QUE    -> las pastillas: combinaciones guardadas por el usuario.

Pinchar una pastilla la manda al destino elegido: con SALIDA cambia el motor
global, con una capa cambia SOLO esa capa y el resto sigue igual. Con una capa
elegida sus ajustes salen en MOTORES (la tarjeta de propiedades se mueve, no
se duplica: dos formularios para lo mismo se desincronizan a la primera).

Las pastillas son configurables: motor + preset + ajustes y su nombre, con
'Configurar pastillas'. Persisten en data/slots.json (gitignorado, es de cada
instalacion). De fabrica vienen los cinco motores de siempre, asi que quien
actualice se encuentra lo mismo que tenia. Hydra, Mezcla y projectM nativo
solo pueden ir a la salida, y al intentar mandarlos a una capa se dice.

Comprobado en Chromium por CDP, no con --dump-dom: ese fotografia el DOM al
cargar, antes de que llegue el estado por socket, y daba falsos "esta vacio".
Verificado que disparar sobre una capa deja el motor global intacto, que la
tarjeta de propiedades va y vuelve de su sitio, y que las pastillas nuevas se
guardan en disco.

De paso, dos fallos que aparecieron al probarlo:
- Restaurar la vista guardada corria al principio del fichero y llamaba a
  codigo que usa variables declaradas con let mas abajo: ReferenceError que
  se llevaba por delante el resto del script (socket incluido) y dejaba el
  panel en blanco. Ahora se restaura al final.
- #card-destino no estaba en la lista de 'order' del CSS, asi que caia a 0 y
  se colaba encima de las pastillas pese a ir despues en el HTML.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
hacklab 2026-08-02 16:47:01 +02:00
parent f017246f0e
commit 61543e1987
8 changed files with 602 additions and 146 deletions

View file

@ -96,15 +96,20 @@ main {
}
.column { display: contents; } /* en movil, las columnas no existen */
/* Orden de las tarjetas cuando estan todas en una sola columna (movil) */
/* Orden de las tarjetas cuando estan todas en una sola columna (movil).
Toda tarjeta de <main> tiene que estar en esta lista: la que falte se
queda en order 0 y se cuela LA PRIMERA, por mucho que en el HTML este
abajo. Primero las pastillas (lo que se toca en directo) y justo despues
el destino, que es su pareja: que lanzas / a donde va. */
#card-power { order: 1; }
#card-engines { order: 2; }
#card-audio { order: 3; }
#card-sens { order: 4; }
#ctl-butterchurn, #ctl-editor, #ctl-mixer, #ctl-projectm { order: 5; }
#card-now { order: 6; }
#card-sys { order: 7; }
#net-foot { order: 8; }
#card-destino { order: 3; }
#card-audio { order: 4; }
#card-sens { order: 5; }
#ctl-butterchurn, #ctl-editor, #ctl-mixer, #ctl-projectm { order: 6; }
#card-now { order: 7; }
#card-sys { order: 8; }
#net-foot { order: 9; }
/* --- Disposicion: pantalla ancha (portatil) en dos columnas --- */
@media (min-width: 880px) {
@ -118,31 +123,20 @@ main {
}
/* --- Vistas (pestanas) ---
MOTORES ensena todo menos las tarjetas de mapping, y al reves. La vista
"capa" es MAPPING recortado: solo la previa y las propiedades de UNA capa,
sin la lista, para poder centrarse en su efecto. */
MOTORES ensena todo menos las tarjetas de mapping, y al reves. Salvo la
tarjeta de propiedades de capa, que MOTORES se lleva prestada cuando estas
editando una capa (ver colocarPropiedades en panel.js). */
body[data-view="motores"] [data-vista="mapping"] { display: none !important; }
body[data-view="mapping"] main > .column > :not([data-vista="mapping"]),
body[data-view="capa"] main > .column > :not([data-vista="mapping"]) {
body[data-view="motores"] #destino-props #card-propiedades {
display: block !important;
}
body[data-view="mapping"] main > .column > :not([data-vista="mapping"]) {
display: none !important;
}
body[data-view="capa"] #card-capas { display: none !important; }
body[data-view="mapping"] main,
body[data-view="capa"] main {
body[data-view="mapping"] main {
flex-direction: column; width: 100%; max-width: 900px;
}
body[data-view="mapping"] .column,
body[data-view="capa"] .column { display: contents; }
/* Pestanas de capa: mas pequenas que MOTORES/MAPPING, para que se lean como
lo que son (un atajo a cada capa) y no compitan con las dos principales. */
.tab.tabcapa, .tab.tabnew {
font-size: 0.78em; padding: 6px 10px; letter-spacing: 0.06em;
max-width: 11ch; overflow: hidden; text-overflow: ellipsis;
white-space: nowrap;
}
.tab.tabnew { border-style: dashed; opacity: 0.85; }
.tab.tabnew:hover { opacity: 1; }
body[data-view="mapping"] .column { display: contents; }
/* En pantalla ancha el mapping se reparte: la previsualizacion grande a la
izquierda (que es donde se trabaja) y las capas con sus propiedades a la
@ -159,17 +153,6 @@ body[data-view="capa"] .column { display: contents; }
body[data-view="mapping"] #card-propiedades { grid-area: props; }
/* La previsualizacion manda: que ocupe todo el alto util disponible */
body[data-view="mapping"] #map-preview { aspect-ratio: 16 / 9; }
/* La vista de una capa: previa a la izquierda, sus ajustes a la derecha */
body[data-view="capa"] main {
display: grid; width: 96%; max-width: 1700px;
grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr);
grid-template-areas: "previa props";
align-items: start; align-content: start; gap: 16px;
}
body[data-view="capa"] #card-mapping { grid-area: previa; }
body[data-view="capa"] #card-propiedades { grid-area: props; }
body[data-view="capa"] #map-preview { aspect-ratio: 16 / 9; }
}
/* --- Tarjetas --- */
@ -253,6 +236,40 @@ body[data-view="capa"] .column { display: contents; }
box-shadow: 0 0 20px rgba(180, 255, 0, 0.6);
}
.engine.active small { color: var(--ink); }
/* En modo configurar, la pastilla abierta se marca distinto de la que esta
sonando: naranja = "la estas editando", verde = "es la que se ve". */
.engine.editando {
border-color: var(--orange); border-style: dashed;
box-shadow: 0 0 16px rgba(255, 157, 42, 0.5);
}
.engine.nueva { border-style: dashed; color: var(--dim); }
.engine.nueva strong { font-size: 22px; }
/* --- Fila de destinos (salida / capas) ---
Deliberadamente distintas de las pestanas de arriba: aquellas cambian de
pantalla, estas eligen a donde va lo que dispares. */
.subtabs {
display: flex; flex-wrap: wrap; gap: 8px; justify-content: center;
margin-bottom: 4px;
}
.subtab {
padding: 8px 14px; border-radius: 999px; cursor: pointer;
background: #161d10; border: 2px solid var(--line); color: var(--dim);
font-weight: 700; font-size: 12px; letter-spacing: 0.08em;
max-width: 14ch; overflow: hidden; text-overflow: ellipsis;
white-space: nowrap;
}
.subtab.active {
background: var(--orange); color: var(--ink); border-color: var(--orange);
}
.subtab.nueva { border-style: dashed; }
#destino-props { margin-top: 12px; }
/* Prestada de MAPPING: dentro de MOTORES no lleva su propio marco, que
quedaria como una tarjeta dentro de otra */
#destino-props #card-propiedades {
background: none; border: none; padding: 0; border-radius: 0;
}
.cmd.del { color: #ff8a7a; }
/* --- Botones de comando --- */
.cmd, .sysbtn {