FOSFENO/docs/pendiente.md
hacklab f017246f0e Capas independientes, projectM en el mapping y catalogo de la galeria
Mapping
- Los clips salian del reves: mapper.js activaba UNPACK_FLIP_Y_WEBGL, pero el
  modelo va con origen arriba-izquierda y texImage2D ya sube la primera fila
  en t=0, asi que el flip la mandaba al final. Comprobado renderizando el
  mapper real en Chromium headless con una fuente mitad roja / mitad azul.
- projectM se puede usar YA en una capa: los .milk de data/presets-projectm se
  traducen a Butterchurn en el navegador al elegirlos (milkdrop-preset-
  converter). La capa MilkDrop gana 'biblioteca' (butter | projectm) sin
  cambiar su firma, para no recrear el contexto WebGL al cambiar de una a otra.
  Medido: 100/100 presets de una muestra convierten, 84/84 de los que llevan
  shaders warp/comp; ~7 ms por preset.
- Cada capa tiene su pestana arriba y su propia vista, y '+ CAPA' crea una y
  entra en ella: con varias capas, ir y volver a MAPPING no era viable.
- Dos capas MilkDrop sin preset ya no salen identicas (cogian el indice 0):
  cada instancia elige uno al azar y lo escribe en el estado.
- Una capa nueva ya no nace en la fuente "motor", que es el lienzo del motor
  activo y hacia que dos capas ensenaran lo mismo.

Galeria de visuales
- scripts/catalogar-visuales.py: ficha de cada clip (pelicula, personajes,
  duracion) y, sobre todo, si es una silueta de verdad y cuanta figura tiene.
  Distingue silueta de corte crudo por el negro puro del fondo: 0,63-0,90
  frente a 0,04-0,06, sin zona gris.
- El panel lista los clips agrupados por pelicula, con nombre legible y aviso
  de los que casi no tienen figura, en vez del nombre del archivo.
- Soporte de siluetas con canal alfa (.webm VP9): transparencia de verdad, sin
  recorte por luminancia. El shader del mapper ya la respeta.

Documentacion
- docs/visuales.md nuevo; pendiente.md al dia con lo hecho y lo que queda.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-02 14:56:01 +02:00

162 lines
7.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Pendiente
Lo que sabemos que falta o falla, con el diagnóstico ya hecho para no volver a
investigarlo desde cero. Ordenado por lo que más duele.
---
## 1. Las capas no son de verdad independientes
**Lo que pasa.** Se pueden poner dos capas con visuales MilkDrop, pero acaban
siendo **la misma imagen**. Y no hay forma de decir "en esta zona el Mezclador,
en esta otra Butter", configurando cada una por su cuenta.
Son **tres cosas distintas** mezcladas en el mismo síntoma:
### 1a. Dos capas Butter sin preset elegido salen idénticas — ✅ HECHO
`web/stage/layers.js`, en `crearButter()`, hacía:
```js
let i = Math.max(0, nombres.indexOf(f.preset));
```
Con `preset: ""` (lo que quedaba si la lista de presets aún no había llegado
al panel al crear la capa), `indexOf("")` devuelve `-1` y el `Math.max(0, -1)`
lo dejaba en **0**: todas las capas así arrancaban en el mismo preset.
**Cómo quedó:** sin preset elegido, cada instancia coge uno **al azar** y lo
devuelve en `presetElegido`. `sync()` avisa por `deps.onPreset(id, preset)`,
que `stage.js` (`anotarPresetDeCapa`) escribe en el estado con `set_mapping`,
así que el panel enseña cuál le tocó en vez de dejar el desplegable en blanco.
No recrea la instancia: la firma de una capa butter sigue siendo el tipo a
secas.
### 1b. Las capas puestas en "El motor de MOTORES" comparten imagen — ✅ HECHO
Esa fuente es, literalmente, el lienzo del motor activo. Dos capas así van a
enseñar lo mismo siempre — no es un fallo, es lo que significa. El problema era
que **era la fuente por defecto** de toda capa nueva, así que el primer
resultado que veía cualquiera era "dos capas iguales".
**Cómo quedó:** una capa nueva ya no nace en "motor". `panel.js` tiene
`fuenteDeCapaNueva()`, que la estrena en MilkDrop con preset al azar
(contenido distinto desde el primer clic) y solo cae en "motor" si Butterchurn
todavía no ha dado su lista de presets. Lo usan tanto `+ Capa` como
`Máscara → Capa`.
### 1c. Falta el Mezclador (y Hydra) como fuente de capa — *(el trabajo de verdad)*
Hoy las fuentes son: motor, butter, shader, clip, cámara, negro. **No está el
Mezclador**, así que "una zona con el Mezclador y otra con Butter" solo se
puede hacer vía "motor", y entonces manda el selector global.
Por qué no está: el Mezclador **es** Hydra (genera código Hydra y lo ejecuta), y
Hydra está montado como instancia única global (`makeGlobal: true`, con `s0`,
`s1`, `o0` en el espacio global). Para tener dos mezcladores independientes hay
que instanciar Hydra varias veces con `makeGlobal: false` y usar la API por
instancia (`h.synth.src(...)`), lo que obliga a reescribir `buildMixerCode` para
que no dependa de los nombres globales.
**Coste realista:** medio día, más el gasto de GPU de un Hydra por capa. Antes
de meterse, decidir si compensa frente a la alternativa barata: dejar el
Mezclador solo como motor a pantalla completa y que las capas tiren de
MilkDrop/shader/clip, que es lo que ya funciona.
### 1d. Los dos paneles no están relacionados
MOTORES y MAPPING van cada uno por su lado: el preset que eliges en el motor
Butter y el de una capa MilkDrop son listas distintas, no comparten favoritos,
y lo que tocas en uno no se refleja en el otro.
**Hacia dónde:** una sola biblioteca de presets y una sola lista de favoritos,
usada por el motor Butter, por las capas del mapping y por projectM. Esto se
solapa con el punto 2: es el mismo trabajo de unificación.
---
## 2. projectM en el mapper — ✅ HECHO (camino A)
**Lo que pasaba.** Al elegir projectM no había forma de mapearlo ni de usarlo
en una capa, y ahí está **la biblioteca de verdad**: 9795 presets `.milk` en 11
categorías y 189 visuales. Butterchurn solo trae ~100 propios.
**Por qué no se podía.** projectM es un proceso nativo que pinta en su propia
ventana X11/Wayland. El compositor de mapping es WebGL dentro del navegador y
solo puede usar como textura lo que vive en la página.
**Cómo quedó.** Se descartó capturar la ventana (frágil en Wayland) y compilar
projectM a WebAssembly (un proyecto en sí). Se hizo el **camino A**: traducir
los `.milk` a presets de Butterchurn **en el propio navegador**, al elegirlos.
- `web/lib/milkdrop-preset-converter.min.js` (npm `milkdrop-preset-converter`,
añadido a `web/package.json` y a `install.sh`).
- `layers.js``cargarMilk(ruta)`: pide el `.milk` al backend (ya los servía),
lo convierte y se lo pasa a `viz.loadPreset()`. Cachea **la promesa**, no el
resultado, para que dos capas pidiendo el mismo preset lo conviertan una vez.
- La capa MilkDrop tiene ahora `biblioteca: "butter" | "projectm"`. La firma de
la capa **sigue siendo `'butter'`**, así que cambiar de biblioteca no recrea
la instancia ni gasta un contexto WebGL más.
- El panel tiene selector de biblioteca y, con projectM, los tres niveles
(categoría / visual / variante) más un botón de "uno al azar".
**Medido, no supuesto:**
- **100/100** presets de una muestra repartida por toda la biblioteca se
convierten sin excepción, incluidos **84/84** de los que llevan shaders
`warp_1`/`comp_1` (que eran justo los dudosos).
- Conversión de un `.milk` real en el navegador: **7 ms**.
- Una capa del mapper con `Dancer/Glowsticks/285.milk` renderiza sin un solo
aviso del escenario.
> Cuidado al medir esto: si el `.milk` no se descarga, Butterchurn **sigue
> pintando su preset de reserva**. Una prueba que solo mire "¿hay píxeles
> encendidos?" da OK igual. Por eso la comprobación exige además que el
> escenario no haya soltado ningún aviso. La primera versión de la prueba dio
> un falso OK exactamente por esto.
**Lo que queda de este punto:** la conversión no es perfecta al 100 % en
fidelidad — algún shader complejo puede verse distinto del original en
projectM. Se convierte y se ve, pero si un preset no convence, la salida es
probar otra variante. Y falta unificar los favoritos entre el motor projectM
y las capas (parte del punto 1d).
---
## 3. Los clips salían del revés en el mapping — ✅ ARREGLADO
**Lo que pasaba.** Al poner un vídeo en una capa del mapping, salía volteado
verticalmente (boca abajo).
**Por qué.** `web/stage/mapper.js`, en `initGL()`, hacía
`gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true)`. Pero el modelo del mapper va
con el origen **arriba-izquierda** (`vUV.y = 0` es el borde de arriba de la
superficie) y `texImage2D` ya sube la primera fila de la imagen en `t = 0`.
Con el flip puesto, `t = 0` pasaba a ser la ÚLTIMA fila: todo del revés.
Se notaba con los clips porque una visual de MilkDrop es casi simétrica y no
canta.
**Comprobado**, no deducido: con una fuente mitad roja arriba / mitad azul
abajo, renderizando el `mapper.js` real en Chromium headless y leyendo el
píxel de arriba con `readPixels`, antes salía AZUL y ahora sale ROJO.
De paso se midió el **Mezclador** (Hydra, `s1.init({src})`) con la misma
prueba: ese sale bien, no hay que tocarlo. Si alguna vez se ve del revés ahí,
no es este fallo.
> Al medir esto, ojo con `readPixels` sobre un lienzo sin
> `preserveDrawingBuffer`: devuelve negro y es facilísimo leerlo como "está
> volteado". Hay que reservar el contexto con `preserveDrawingBuffer: true`
> ANTES de que la librería llame a `getContext`.
---
## 4. Menor: no hay fundido al cambiar de motor
Pasar de Mezcla a Butter es un corte seco. Dentro de una capa MilkDrop sí hay
transición suave (deslizador de 08 s), pero cruzar **dos motores** exige
renderizar los dos a la vez durante el cruce y fundirlos en el compositor.
Se puede hacer en el mapper (dibujar la capa dos veces, con la fuente vieja
bajando de alfa y la nueva subiendo), pero cuesta tener los dos motores vivos a
la vez unos segundos. Decidir si merece la pena.