sitio: un fondo de color que deriva despacio, y las pastillas de arriba dejan de ser transparentes
Cinco manchas de color en un plano fijo detrás de todo. Funciona porque `section.franja` no tiene fondo propio —sólo un border-top—, así que el color se ve en la página entera; las tarjetas (--papel) siguen opacas y el texto sigue encima de algo quieto. Se animan SÓLO transform, opacity y filter, que las resuelve el compositor. Animar el background de un gradiente a pantalla completa repinta cada cuadro y se nota en el ventilador antes que en los ojos. Y el azar no se pinta cuadro a cuadro: el guion elige un destino nuevo cada ~23 s y la transición de CSS (46 s) interpola, así que entre dos elecciones no corre ni una línea de JS. Cada mancha con su reloj y su desfase: con un intervalo común las cinco cambiarían de rumbo en el mismo instante y el fondo LATIRÍA en vez de derivar. La primera colocación va sin transición, o las cinco saldrían del centro exacto a la vez y el primer minuto sería un floreo. El tema manda cuánta luz hay: en oscuro `screen` sobre la obsidiana; en claro eso lavaría todo a blanco, así que `multiply` con poca fuerza y queda un tinte. Al tocar la perilla se recolocan, o se quedarían con la opacidad del tema viejo hasta el siguiente tic. prefers-reduced-motion recibe el color y no el movimiento — y hay que APAGAR el intervalo, no sólo la transición: con transition:none los saltos quedarían instantáneos cada 23 s, peor que el movimiento que la persona pidió no tener. Y las tres pastillas de la barra (ES/EN/tema) eran background:transparent. Con la barra al 88 % por ahí pasaban las manchas en movimiento y el rótulo perdía contraste A RATOS: legible en una captura y no en la siguiente. Relleno propio al 72 %, 90 % en hover, 94 % la activa. ⚠ No verificado a ojo: en esta caja no corre ningún navegador (el firefox del corpus muere con el NEEDED colgante de libstdc++). Se comprobó la estructura, no el render. Y esta raíz de caddy sirve DIRECTO el árbol de trabajo, así que el cambio ya estaba público al guardar el fichero. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Delta semántico
Ninguna definición cambió: el cambio es de texto, documentación o datos.
1 archivos · +114 −4
- web/takana-os.net/index.html +114 −4
diff --git a/web/takana-os.net/index.html b/web/takana-os.net/index.html
index 1e501355..08d72477 100644
--- a/web/takana-os.net/index.html
+++ b/web/takana-os.net/index.html
@@ -40,6 +40,45 @@
--acento:#E8834A;--acento2:#E3A63D;
color-scheme:dark}
+/* ── el fondo vivo: cinco manchas de color que derivan despacio ─────────────────────────────
+ Va en un plano FIJO detrás de todo (`z-index:-1`), que funciona porque `section.franja` no
+ tiene fondo propio —sólo un `border-top`—: el color se ve en la página entera y no sólo en los
+ bordes. Las tarjetas (`--papel`) siguen siendo opacas, que es lo que mantiene el texto legible
+ encima de un fondo que se mueve.
+
+ ⚠ **Lo que se anima son `transform`, `opacity` y `filter`, y nada más.** Ésas tres las resuelve
+ el compositor sin repintar; animar el `background` de un gradiente a pantalla completa repinta
+ cada cuadro y en un portátil se nota en el ventilador antes que en los ojos.
+
+ ⚠ Y el movimiento aleatorio NO se hace cuadro a cuadro desde JS: el guion sólo elige un destino
+ nuevo cada varios segundos y la TRANSICIÓN de CSS interpola. Un `requestAnimationFrame` que
+ escribe estilos 60 veces por segundo para mover algo que tarda un minuto en cruzar la pantalla
+ es trabajo tirado.
+
+ `--mezcla` y `--fuerza` son lo que cambia entre temas: en oscuro `screen` suma luz de color
+ sobre la obsidiana; en claro eso lavaría todo a blanco, así que ahí se usa `multiply` con muy
+ poca fuerza y queda un tinte, no una mancha. */
+:root{--mezcla:multiply;--fuerza:.16}
+@media (prefers-color-scheme:dark){:root:not([data-theme="light"]){--mezcla:screen;--fuerza:.52}}
+:root[data-theme="dark"]{--mezcla:screen;--fuerza:.52}
+.aurora{position:fixed;inset:0;z-index:-1;pointer-events:none;overflow:hidden;
+ contain:strict}
+.aurora i{position:absolute;display:block;top:50%;left:50%;
+ width:78vmax;height:78vmax;margin:-39vmax 0 0 -39vmax;border-radius:50%;
+ mix-blend-mode:var(--mezcla);opacity:var(--fuerza);
+ /* El blur es enorme a propósito: sin él se ven cinco círculos, y con él se ve UN campo de color.
+ `will-change` sube las manchas a su propia capa para que el compositor no rehaga el resto. */
+ filter:blur(9vmax);will-change:transform,opacity,filter;
+ transition:transform 46s cubic-bezier(.37,0,.63,1),opacity 46s linear,filter 46s linear}
+.aurora i:nth-child(1){background:radial-gradient(circle,#8A3BD6 0%,rgba(138,59,214,0) 68%)}
+.aurora i:nth-child(2){background:radial-gradient(circle,#1F8FA8 0%,rgba(31,143,168,0) 68%)}
+.aurora i:nth-child(3){background:radial-gradient(circle,#DF6B2A 0%,rgba(223,107,42,0) 68%)}
+.aurora i:nth-child(4){background:radial-gradient(circle,#C2266B 0%,rgba(194,38,107,0) 68%)}
+.aurora i:nth-child(5){background:radial-gradient(circle,#2F6BD8 0%,rgba(47,107,216,0) 68%)}
+/* Quien pide menos movimiento recibe el color y no el movimiento: el fondo sigue siendo colorido,
+ pero se queda quieto. No es un extra — un fondo que deriva puede marear de verdad. */
+@media (prefers-reduced-motion:reduce){.aurora i{transition:none}}
+
*{margin:0;padding:0;box-sizing:border-box}
html{scroll-behavior:smooth}
body{background:var(--fondo);color:var(--texto);font:17px/1.62 var(--sans);
@@ -100,10 +139,19 @@ nav.enlaces{margin-left:auto;display:flex;gap:1.15rem;font-size:.88rem}
nav.enlaces a{color:var(--tenue)}
nav.enlaces a:hover{color:var(--acento)}
.perillas{display:flex;gap:.35rem}
-.perilla{font:500 .76rem/1 var(--sans);color:var(--tenue);background:transparent;
- border:1px solid var(--linea2);border-radius:99px;padding:.42rem .6rem;cursor:pointer}
-.perilla:hover{color:var(--texto);border-color:var(--acento)}
-.perilla.on{color:var(--acento);font-weight:700;border-color:var(--acento)}
+/* ⚠ Estas pastillas eran `background:transparent`, y con el fondo vivo detrás eso dejó de ser
+ gratis: la barra es translúcida (88 %), así que por un control transparente pasaban las manchas
+ de color en movimiento y el rótulo perdía contraste a ratos — legible en una captura y no en la
+ siguiente, que es la peor forma de estar ilegible. Un relleno propio lo ancla sin taparlo. */
+.perilla{font:500 .76rem/1 var(--sans);color:var(--tenue);
+ background:color-mix(in srgb,var(--papel) 72%,transparent);
+ border:1px solid var(--linea2);border-radius:99px;padding:.42rem .6rem;cursor:pointer;
+ transition:background-color .15s,color .15s,border-color .15s}
+.perilla:hover{color:var(--texto);border-color:var(--acento);
+ background:color-mix(in srgb,var(--papel) 90%,transparent)}
+/* La activa va más opaca que las demás: es la que tiene que leerse de un vistazo. */
+.perilla.on{color:var(--acento);font-weight:700;border-color:var(--acento);
+ background:color-mix(in srgb,var(--papel) 94%,transparent)}
@media(max-width:860px){nav.enlaces{display:none}.perillas{margin-left:auto}}
.portada{position:relative;padding:4.6rem 0 2.6rem;overflow:hidden}
@@ -235,6 +283,8 @@ footer.pie{border-top:1px solid var(--linea);background:var(--papel);padding:2.6
</style>
</head>
<body>
+<!-- El fondo vivo. `aria-hidden` porque no dice nada: es color. -->
+<div class="aurora" aria-hidden="true"><i></i><i></i><i></i><i></i><i></i></div>
<svg width="0" height="0" style="position:absolute" aria-hidden="true">
<symbol id="tocapu" viewBox="0 0 748 748">
@@ -828,6 +878,66 @@ footer.pie{border-top:1px solid var(--linea);background:var(--papel);padding:2.6
try{ localStorage.setItem('takana-tema', r.dataset.theme); }catch(e){}
});
})();
+
+/* ── el fondo vivo: elegir destinos, no pintar cuadros ─────────────────────────────────────────
+ El guion hace UNA cosa: cada tanto le da a cada mancha una posición, un tamaño, un giro de tono
+ y una opacidad nuevos. La interpolación es de CSS (`transition: … 46s`), así que entre dos
+ elecciones no corre ni una línea de JavaScript.
+
+ ⚠ **La primera colocación va sin transición y las siguientes con ella.** Si la primera se
+ transicionara, las cinco manchas saldrían del centro exacto de la pantalla a la vez y el primer
+ minuto de la página sería un floreo; arrancan ya repartidas y de ahí derivan.
+
+ ⚠ **`prefers-reduced-motion` se respeta de verdad**, o sea que no se programa el intervalo: con
+ el CSS solo, el `transition:none` dejaría los saltos INSTANTÁNEOS cada 23 s, que es peor que el
+ movimiento continuo que la persona pidió no tener. */
+(function(){
+ var capa = document.querySelector('.aurora');
+ if (!capa) return;
+ var manchas = capa.querySelectorAll('i');
+ var quieto = window.matchMedia && window.matchMedia('(prefers-reduced-motion:reduce)').matches;
+
+ function az(a, b){ return a + Math.random() * (b - a); }
+
+ function colocar(m, i){
+ // Repartidas por la pantalla, pero sin salirse tanto que la mancha deje de aportar color.
+ m.style.transform = 'translate(' + az(-42, 42).toFixed(1) + 'vw,' + az(-40, 40).toFixed(1) + 'vh)'
+ + ' scale(' + az(0.62, 1.22).toFixed(3) + ')';
+ // El giro de tono es lo que hace que el conjunto no repita nunca la misma combinación: cada
+ // mancha parte de un color distinto y cada una gira por su cuenta.
+ m.style.filter = 'blur(9vmax) hue-rotate(' + az(-70, 70).toFixed(1) + 'deg)';
+ // La opacidad se mueve alrededor de la del tema, no en absoluto: así el tema sigue mandando
+ // cuánto color hay, y el azar sólo lo respira.
+ var base = parseFloat(getComputedStyle(capa).getPropertyValue('--fuerza')) || 0.4;
+ m.style.opacity = (base * az(0.55, 1.25)).toFixed(3);
+ }
+
+ // Arranque: sin transición, para que no salgan todas del centro.
+ manchas.forEach(function(m, i){
+ var t = m.style.transition; m.style.transition = 'none';
+ colocar(m, i);
+ // Un reflow forzado entre medio, o el navegador agrupa los dos cambios y la transición vuelve
+ // a aplicarse al primer destino — que es justo el floreo que esto evita.
+ void m.offsetWidth;
+ m.style.transition = t;
+ });
+
+ if (quieto) return;
+ // Cada mancha en su propio reloj y con su propio desfase: con un intervalo común las cinco
+ // cambiarían de rumbo en el mismo instante y el fondo latiría en vez de derivar.
+ manchas.forEach(function(m, i){
+ setTimeout(function(){
+ setInterval(function(){ colocar(m, i); }, 23000 + i * 3100);
+ }, i * 4300);
+ });
+
+ // El tema cambia `--fuerza`; sin volver a colocar, las manchas se quedan con la opacidad del tema
+ // viejo hasta el siguiente tic (23 s mirando un fondo que no corresponde).
+ var perilla = document.getElementById('tema');
+ if (perilla) perilla.addEventListener('click', function(){
+ setTimeout(function(){ manchas.forEach(colocar); }, 30);
+ });
+})();
</script>
</body>
</html>