|
|
|
|
@ -25,13 +25,22 @@
|
|
|
|
|
* programa que no compila, el componente no pinta y debajo sigue la imagen
|
|
|
|
|
* de siempre. Un fondo decorativo no puede tumbar una portada.
|
|
|
|
|
*/
|
|
|
|
|
import { tema } from '$lib/tema.svelte';
|
|
|
|
|
import { tema, type Tema } from '$lib/tema.svelte';
|
|
|
|
|
|
|
|
|
|
/** Densidad máxima. En una pantalla 4K, pintar cada píxel real no compensa. */
|
|
|
|
|
const DPR_MAXIMO = 1.5;
|
|
|
|
|
|
|
|
|
|
let lienzo = $state<HTMLCanvasElement | null>(null);
|
|
|
|
|
let activo = $state(false);
|
|
|
|
|
/**
|
|
|
|
|
* Cambia solo los colores del programa que ya está dibujando.
|
|
|
|
|
*
|
|
|
|
|
* Va separado de la inicialización porque leer `tema.actual` dentro de aquel
|
|
|
|
|
* efecto hacía que Svelte desmontara WebGL al alternar el tema. Su limpieza
|
|
|
|
|
* pierde el contexto deliberadamente y un contexto perdido no se puede volver
|
|
|
|
|
* a montar de inmediato sobre el mismo canvas: por eso las ondas desaparecían.
|
|
|
|
|
*/
|
|
|
|
|
let cambiarPaleta = $state<((actual: Tema) => void) | null>(null);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* La paleta sale de los colores de marca, convertida a RGB lineal: el shader
|
|
|
|
|
@ -51,10 +60,10 @@
|
|
|
|
|
[0.0636, 0.1453, 0.3199]
|
|
|
|
|
],
|
|
|
|
|
claro: [
|
|
|
|
|
[0.8849, 0.9147, 0.9744],
|
|
|
|
|
[0.6679, 0.7334, 0.8648],
|
|
|
|
|
[0.4187, 0.52, 0.7112],
|
|
|
|
|
[0.1813, 0.2974, 0.5092]
|
|
|
|
|
[0.35, 0.48, 0.72],
|
|
|
|
|
[0.18, 0.32, 0.58],
|
|
|
|
|
[0.07, 0.19, 0.42],
|
|
|
|
|
[0.02, 0.08, 0.24]
|
|
|
|
|
]
|
|
|
|
|
} as const;
|
|
|
|
|
|
|
|
|
|
@ -188,8 +197,11 @@ void main() {
|
|
|
|
|
const uTiempo = gl.getUniformLocation(programa, 'u_tiempo');
|
|
|
|
|
const uPaleta = gl.getUniformLocation(programa, 'u_paleta');
|
|
|
|
|
|
|
|
|
|
const paleta = PALETAS[tema.actual] ?? PALETAS.oscuro;
|
|
|
|
|
gl.uniform3fv(uPaleta, new Float32Array(paleta.flat()));
|
|
|
|
|
const aplicarPaleta = (actual: Tema) => {
|
|
|
|
|
const paleta = PALETAS[actual] ?? PALETAS.oscuro;
|
|
|
|
|
gl.uniform3fv(uPaleta, new Float32Array(paleta.flat()));
|
|
|
|
|
};
|
|
|
|
|
cambiarPaleta = aplicarPaleta;
|
|
|
|
|
|
|
|
|
|
function medir() {
|
|
|
|
|
if (!lienzo || !gl) return;
|
|
|
|
|
@ -253,6 +265,7 @@ void main() {
|
|
|
|
|
arrancar();
|
|
|
|
|
|
|
|
|
|
return () => {
|
|
|
|
|
if (cambiarPaleta === aplicarPaleta) cambiarPaleta = null;
|
|
|
|
|
parar();
|
|
|
|
|
observador.disconnect();
|
|
|
|
|
document.removeEventListener('visibilitychange', alCambiarDePestana);
|
|
|
|
|
@ -266,6 +279,15 @@ void main() {
|
|
|
|
|
gl.getExtension('WEBGL_lose_context')?.loseContext();
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Este efecto sí sigue el tema, pero no toca el ciclo de vida del contexto:
|
|
|
|
|
* doce números nuevos en un uniforme bastan para recolorear el siguiente
|
|
|
|
|
* fotograma sin recompilar shaders, perder animación ni dejar un parpadeo.
|
|
|
|
|
*/
|
|
|
|
|
$effect(() => {
|
|
|
|
|
cambiarPaleta?.(tema.actual);
|
|
|
|
|
});
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<!--
|
|
|
|
|
|