CYBERSENSEAI · REDISEÑO DE HOME · CONCEPTO "XAIOS"
Esta guía documenta el concepto, el sistema visual y la técnica de la home XAIOS: una secuencia de boot en terminal que cede el control a un diagrama 3D explosionado de las capas del sistema operativo, renderizado con un motor WebGL escrito a mano, sin ninguna librería externa.
XAIOS es el sistema operativo propietario de CyberSenseAI para Personas IA. La tesis del diseño: si el producto es un OS, la web debe comportarse como un OS. De ahí las dos piezas centrales:
sessionStorage y desaparece por completo bajo prefers-reduced-motion.Para un comprador enterprise (CTO/CISO) el tono es "espectáculo con precisión": telemetría real en pantalla, códigos de capa (soberania.xk), un monitor de equipo estilo htop y una checklist de verificación con los 8 criterios enterprise. Nada de circo: cada efecto lleva información.
Un solo acento. El cian se reserva para lo que importa: la capa activa, los estados [ OK ], los CTA y las palabras clave. Todo lo demás vive en la escala titanio sobre negro puro, lo que hace que el blending aditivo del WebGL brille sin esfuerzo.
Display. Angular, de inspiración técnica tailandesa-industrial, con esquinas chaflanadas que riman con los slabs octogonales del diagrama 3D. Pesos 300–700. Titulares, wordmark y cifras.
Sistema. La voz del OS: log de boot, prompts, telemetría, tablas, etiquetas y todo el microcopy. Su regularidad da credibilidad de terminal real.
Composición: grid asimétrico con el stack 3D desplazado a la derecha (offset NDC +0.24), numeración de sección gigante en outline, reglas oblicuas (skewY(-1.2deg)), grano de ruido SVG al 4% y viñeta radial para atmósfera.
El boot es una máquina de estados mínima: un array de líneas con retardos por línea, una barra de progreso y tres salidas (completado, ESC/omitir, visita repetida). Código real de la página:
var LINES = [ {t:40, h:'<span class="h">XAIOS BIOS v5.0 — CyberSenseAI SL</span>'}, {t:70, h:'[0.001] Comprobando perímetro de seguridad … [ OK ]'}, /* … kernel, /soberania, aislamiento, gobernanza, ENS·ISO·GDPR … */ {t:150, h:'[0.803] Despertando a SoulBot … [ EN LÍNEA ]'} ]; function next(){ if(i >= LINES.length){ setTimeout(function(){ finish(false); }, 260); return; } log.innerHTML += LINES[i].h + '\n' + '<span class="cur"></span>'; bar.style.transform = 'scaleX(' + ((i+1)/LINES.length) + ')'; i++; setTimeout(next, LINES[i-1].t); }
Al terminar, body.booted dispara la carga orquestada del hero: letras del wordmark en cascada (cubic-bezier(.19,1,.22,1)), un glitch de 500 ms, y reveals escalonados de tagline, CTA, prompt y chips — una sola coreografía, no mil micro-efectos.
Sin three.js ni ninguna dependencia: ~200 líneas de motor. La geometría son ~1.100 segmentos GL_LINES (6 slabs octogonales con rejilla, conectores verticales, escuadras HUD, un octaedro "Persona" y un suelo con desvanecimiento radial) más 240 partículas GL_POINTS que atraviesan el stack. Un draw call para líneas, otro para puntos, blending aditivo sobre negro puro.
attribute vec3 aPos; attribute float aLayer, aKind, aFade; uniform float uSpread,uRotY,uRotX,uDist,uAspect,uOffX,uOffY,uZoom; uniform mediump float uTime; void main(){ vec3 p = aPos; p.y += (aLayer - 2.5) * uSpread; // explosión if(aKind > 3.5 && aKind < 4.5){ p.y += 0.1*sin(uTime*1.35); } // octaedro flota float cy=cos(uRotY), sy=sin(uRotY); // órbita Y p = vec3(cy*p.x+sy*p.z, p.y, -sy*p.x+cy*p.z); float cx=cos(uRotX), sx=sin(uRotX); // tilt X p = vec3(p.x, cx*p.y-sx*p.z, sx*p.y+cx*p.z); p.z -= uDist; float w = -p.z; // perspectiva manual: clip w gl_Position = vec4(p.x*uZoom/uAspect + uOffX*w, p.y*uZoom + uOffY*w, 0.0, w); }
No hay matrices 4×4: dos rotaciones, una traslación y w = −z bastan, porque las líneas con blending aditivo no necesitan depth buffer. uOffX/uOffY desplazan el encuadre en NDC (el stack vive a la derecha del texto y baja un poco en el hero).
precision mediump float; varying float vLayer, vKind, vFade; uniform float uActive, uTime; const vec3 CIAN = vec3(0.0, 0.898, 1.0); const vec3 TITAN = vec3(0.545, 0.573, 0.596); void main(){ float hi = smoothstep(1.15, 0.0, abs(vLayer - uActive)); vec3 col = mix(TITAN, CIAN, hi); float a = mix(0.34, 1.0, hi); // resto titanio, activa cian // aKind: 1 rejilla · 2 conectores · 3 escuadras · 4 octaedro · 5 suelo gl_FragColor = vec4(col, a); // blend SRC_ALPHA, ONE (aditivo) }
Lección de guerra: el programa de líneas no linkaba en algunos drivers porque uTime era highp implícito en el vertex y mediump en el fragment — precisión de uniforms compartidos debe coincidir. Se declara mediump en ambos.
var t = clamp(-rect.top / (seccion.offsetHeight - vh), 0, 1); // 0→1 en 640vh tg.spread = .34 + easeInOut(clamp(t/.32, 0, 1)) * .74; // explosión tg.active = (t < .04) ? -2 : ((t-.06)/.88) * 5.0; // L0 → L5 tg.rotY = .55 + t*2.35; // órbita 135° // cada frame: st.x = lerp(st.x, tg.x, 0.085) — muelle crítico, sin saltos
La sección mide 640vh con un viewport position:sticky. Los seis pasos del HUD (paneles con crossfade + raíl de navegación clicable) se derivan del mismo t, así que canvas y DOM nunca se desincronizan. La telemetría de la esquina (SPREAD · CAPA · ÓRBITA) lee el estado real del motor.
Lección de guerra (pasada 1): el conmutador a Canvas 2D existía pero no estaba conectado. Un contexto GL perdido dejaba el bucle rAF muerto y el compositor pintando memoria sin inicializar: niebla blanca sobre media página. Definir el fallback no basta; hay que cablear cada ruta de fallo:
render sigue indefinido (no hay contexto o los shaders no compilan/linkan), se conmuta a Canvas 2D en el acto: mismo array de segmentos, proyectados a mano por una proj() que replica los shaders en JS. El canvas se sustituye por un clon limpio para poder pedir contexto 2D.webglcontextlost: si el proceso GPU muere en caliente (pestañas de fondo, drivers), el evento dispara la misma conmutación con preventDefault().render puede matar la cadena rAF: primer fallo → 2D; si el propio 2D falla → escena en negro digno, la página sigue viva.readPixels, posible gracias a preserveDrawingBuffer): por ahí nunca pasan trazos, deben ser ~negras. Si ≥3 salen claras, la imagen es basura → Canvas 2D. Coste total: dos lecturas de 1 px en toda la vida de la página.prefers-reduced-motion: sin boot, sin bucle rAF — la escena se renderiza bajo demanda en cada scroll, con tiempo congelado; los reveals y contadores aparecen ya resueltos.devicePixelRatio limitado a 2, y el render se detiene (visibility:hidden) cuando el canvas queda fuera de la historia. 60 fps estables.El diagrama responde a la mano: en desktop (pointer:fine, nunca bajo reduced-motion) la posición del cursor añade ±0.22 rad de órbita y ±0.12 rad de tilt a los targets de cámara, suavizados con el mismo muelle del scroll. La escena deja de ser un vídeo y pasa a ser un sistema que te siente.
| DECISIÓN | POR QUÉ |
|---|---|
| Boot de ~1,7 s, omitible | Suficiente para el ritual, corto para no estorbar (se comprimió un 40% en la pasada 1: 500k primeras impresiones no esperan); ESC + sessionStorage protegen la visita repetida. El log es copy de producto, no relleno. El destello de traspaso baja a opacidad 0.22 por fotosensibilidad. |
| El terminal del hero teclea | El prompt xaios status se escribe carácter a carácter al recibir el control del BIOS — el traspaso continúa dentro del hero. Texto íntegro en HTML y en aria-label: sin JS o con reduced-motion no se pierde nada. |
| Todas las terminales viven | La sesión de SoulBot y el xaios init final también se teclean al entrar en viewport, conservando los spans de color del terminal. Antes de animar se inyecta una copia sr-only y el bloque animado pasa a aria-hidden; con reduced-motion el texto del HTML no se toca. Una "sesión en vivo" pre-impresa rompía la ficción del OS. |
| L gigante + progreso en el raíl | 640vh de viaje necesitan brújula: un identificador de capa fantasma (outline cian al 15%, L0…L5, con barrido al cambiar) ancla el ojo y llena el vacío centro-derecha, y una línea de progreso cian sube por los diamantes del raíl (transform-only, sin layout). El boot, además, se omite con cualquier click/tap — no solo ESC — y el log reserva su altura final (11 líneas) para no recolocarse a cada línea. |
| Slabs octogonales, no cajas | El chaflán rima con Chakra Petch y con la iconografía HUD; una caja leería "maqueta", el octógono lee "pieza mecanizada". |
| Wireframe aditivo, sin caras sólidas | Un OS de seguridad se enseña por dentro: transparencia literal. Además elimina el depth-sorting y mantiene el motor en 2 draw calls. |
| 100% procedural, 0 imágenes | Todo el arte (stack, partículas, grano, viñeta) se genera en runtime. Página autocontenida: un solo HTML + Google Fonts. |
| Sin librerías | El listón era demostrar capacidad: matemáticas de cámara, GLSL y orquestación a mano caben en ~20 KB de JS legible. |
| Español nativo, tono kernel | «Montando /soberania», «sandbox asignado p-101»: el lenguaje Unix en español refuerza que XAIOS es un producto real, no una metáfora. |
Assets externos: ninguno salvo las dos familias de Google Fonts. No se generaron imágenes: el concepto es íntegramente procedural.
#464d54 (2.45:1) a #6d7780 (4.6:1) — todos los micro-textos (telemetría, statusbar, metadatos) cumplen AA sobre negro puro. Suelo de micro-tipografía en .62rem.--ease: cubic-bezier(.19,1,.22,1) para paneles, stats, subrayados y verticales; la barra de boot deja de ser lineal; ninguna transición usa all.CONOCER AICREI lleva base rgba(2,12,14,.72) — el wireframe de la escena ya no atraviesa el rótulo en el CTA final; en móvil, un scrim radial protege el copy del hero.aria-expanded, paneles L0–L5 con aria-hidden sincronizado y raíl con aria-pressed.<noscript> oculta el overlay de boot (que sin JS cubría todo en negro para siempre) y resuelve de golpe todos los reveals orquestados (header, hero, .rv). Regla aprendida: toda opacidad-0 inicial necesita su ruta de escape sin script.<main> envolviendo todo el contenido, paneles L0–L5 con aria-hidden y raíl con aria-pressed declarados ya en el HTML servido (antes solo existían tras el primer frame de JS).role="dialog" + aria-modal, foco al botón de cierre al abrir, retorno del foco al burger al cerrar y trampa de Tab dentro del overlay.100svh (con fallback vh) — la barra de URL de móvil ya no descuadra el primer pantallazo ni hace saltar la escena sticky al colapsar.opacity/visibility del canvas solo se escriben cuando cambian (caché de último valor, reseteada al clonar el canvas en el conmutador 2D); código muerto eliminado del mapeo de scroll.[✓] declara texto alternativo vacío (content:"…" / "") para no verbalizarse en lectores de pantalla.