01 · ConceptoLa metáfora manda
El producto de CyberSenseAI son Personas IA que se incorporan a equipos humanos. La colmena es la metáfora exacta: individuos distintos, celdas contiguas, un producto común. Cada decisión visual deriva de ahí:
- La retícula hexagonal es la interfaz: héroe, estadísticas, verticales y diagrama comparten la misma celda.
- Los datos son miel: pulsos ámbar que viajan de celda en celda en el canvas, gotas SMIL en el diagrama de equipo, celdas SVG que se llenan al hacer scroll.
- Humanos y Personas IA se representan con dos glifos distintos pero equivalentes en jerarquía: perla blanca (humano) y hexágono ámbar rotando (Persona IA). Cooperan en la misma retícula — nunca uno dentro del otro.
02 · Paleta y tipografíaÁmbar miel · negro cera · blanco panal
Un dominante casi monocromo (cera) con un solo eje de acento (la familia miel) y el blanco panal reservado para lo humano. Nada de gradientes fríos: hasta el fondo del canvas es un degradado de ceras.
Fraunces display
Serif variable con calidez de miel y wonk editorial. Titulares en 420–530 de peso; las palabras clave en itálica ámbar.
Archivo — texto e interfaz
Spline Sans Mono — datos
Grotesk seca para el cuerpo; la mono, en mayúsculas espaciadas, etiqueta celdas, cifras y certificaciones como si fueran marcas de apiario.
03 · La técnica centralCanvas 2D: la colmena que respira
El héroe es un canvas 2D escrito a mano (~200 líneas). No hay mundo pre-generado: la colmena es
infinita y determinista. Cada celda axial (q, r) obtiene su papel — vacía, miel,
humano o Persona IA — de un hash entero sin estado, así el mundo es estable entre fotogramas y
entre visitas, sin guardar nada:
function hash(q, r){
var n = q*374761393 + r*668265263;
n = (n ^ (n>>13)) | 0;
n = (n * 1274126177) | 0;
n = (n ^ (n>>16)) >>> 0;
return n / 4294967295; // 0..1 estable por celda
}
// papel de la celda: <4% humanos, <8.5% Personas IA, <15% miel
La cámara vive en coordenadas mundo y el scroll del héroe (230vh con viewport sticky) gobierna el zoom:
de s = 2.5 (celdas en primer plano) a s = 1.05 (la colonia entera), con
deriva senoidal lenta para que nunca esté quieta:
var p = smooth(progresoHero); // scroll 0..1 suavizado cam.s = 2.5 - 1.45*p; // zoom out orquestado cam.x = Math.sin(t*0.05)*26 + 30; // deriva de enjambre ctx.setTransform(DPR*s, 0, 0, DPR*s, DPR*(W/2 - cam.x*s), DPR*(H/2 - cam.y*s)); // solo se itera el rango (q, r) visible tras invertir la transformación
Los flujos de miel-datos son pulsos que nacen en una celda ocupada y caminan 3–7 pasos por
vecinos axiales (prohibido deshacer el último paso), dibujados como estela ámbar + sprite de brillo
pre-renderizado. Las celdas de miel se llenan con un gradiente recortado por el propio trazado
hexagonal (clip()), con menisco brillante. El cursor también participa: la celda bajo
el ratón se enciende, sus vecinas suben de opacidad y un halo ambiental de miel — un único
drawImage del sprite de brillo en coordenadas mundo — lo sigue por la retícula.
La colmena también responde al tacto: un clic o toque sobre el canvas hace nacer una ráfaga de cinco pulsos en la celda tocada, que se reparten por sus vecinas con el mismo caminante axial de los pulsos ambientales (con tope de pulsos vivos para no comprometer los 60 fps). Las celdas que contienen miel refuerzan además la opacidad de su pared: sin ese refuerzo el relleno leía como un rectángulo flotante en vez de una celda cerrada. Y la misma mecánica cierra la carga: dos segundos después del revelado del titular, una ráfaga de bienvenida nace en la celda etiquetada de SoulBot — la colmena saluda reutilizando el código del tacto, sin una línea nueva de dibujo (y se omite si el visitante ya hizo scroll).
El scroll no solo aleja la cámara: dispara una ola de activación. Los umbrales del hash que deciden el papel de cada celda crecen con el progreso — a colmena abierta hay más humanos, más Personas IA, más miel y más pulsos simultáneos. La zona del titular nace despejada (sin ocupantes detrás del texto) y solo se puebla cuando el copy ya salió de escena, desvanecido y elevado por la misma coreografía. Debajo de todo, una capa lejana de panal macro (celdas 3× a mitad de parallax) da profundidad de campo con ~30 hexágonos extra por fotograma.
04 · RendimientoUn stroke por opacidad, no por celda
Con el zoom abierto hay ~340 celdas visibles. Trazarlas una a una (340 stroke() con
su cambio de estilo) era el cuello de botella medido en headless. La solución: cuantizar la opacidad
de cada pared de cera y acumular los hexágonos en un Path2D por cubo —
el fotograma pasa de cientos de strokes a ~15:
var cubo = Math.round(alfa*40); // pasos de 0.025
var pth = buckets[cubo] || (buckets[cubo] = new Path2D());
hexEnPath(pth, c.x, c.y, R-2.5);
// ...tras el bucle:
for (var kb in buckets){
ctx.strokeStyle = "rgba(242,169,28," + (kb/40).toFixed(3) + ")";
ctx.stroke(buckets[kb]);
}
- Gradiente de fondo cacheado en
resize(), no por fotograma. - Brillos como sprites de 64px pre-renderizados (
drawImage, no gradientes radiales en vivo). devicePixelRatiolimitado a 1.75; el bucle se pausa si el héroe sale del viewport o la pestaña se oculta.- Paso de tiempo real, no por fotograma: los pulsos avanzan con
dtmedido entre fotogramas (con tope de 50 ms para las reanudaciones). Sumarvel/60por fotograma iba al doble de velocidad en las pantallas de 120 Hz — la mitad de los móviles actuales — y a la mitad bajo jank. La probabilidad de nacimiento de pulsos también se expresa por segundo y se escala pordt. resize()con guarda: la barra de URL y el teclado móviles disparanresizesin cambiar las dimensiones efectivas; si ancho, alto y DPR coinciden, no se destruye el buffer del canvas ni se recrea el gradiente.- Nada de estilo sobre lo invisible: las etiquetas de celda van ocultas por CSS en ≤640px,
así que la proyección mundo→pantalla (tres escrituras de
transform/opacitypor fotograma) se salta entera en móvil. Conprefers-reduced-motion, el repintado por scroll solo ocurre si el héroe está en viewport.
05 · Detalles que venden la metáforaEtiquetas proyectadas y gotas SMIL
Tres celdas fijas del mundo (SoulBot · Persona IA, Humana · Operaciones,
Persona IA · Análisis) llevan etiquetas HTML reales, proyectadas cada fotograma de
coordenadas mundo a pantalla con la misma cámara del canvas — se mueven, escalan y se desvanecen
con el zoom como si estuvieran dentro de la colmena:
var sx = (cc.x - cam.x)*s + W/2, sy = (cc.y - cam.y)*s + H/2;
tag.style.transform = "translate("+sx+"px,"+sy+"px) translateY(-50%)";
tag.style.opacity = clamp(1 - progresoHero*2.4, 0, 1);
En el diagrama de equipo híbrido (3 humanos + 2 Personas IA + tablero compartido), las gotas de
miel-datos viajan con SMIL animateMotion dentro del SVG: escalan con el
viewBox en cualquier ancho — un begin negativo las arranca ya en mitad
del camino, sin destello inicial en el origen. Las celdas de estadísticas se llenan con un
<rect> recortado por clipPath hexagonal cuya transformación se
transiciona por CSS al entrar en viewport, sincronizada con contadores en requestAnimationFrame.
06 · Movimiento y accesibilidadUna carga orquestada, un fallback digno
- Carga: el revelado espera a
document.fonts.ready(con red de seguridad de 900 ms): el canvas funde desde negro, titular palabra a palabra con máscaras de recorte, luego subtítulo, CTAs y etiquetas de celda. Al terminar, las máscaras liberan suoverflowpara que la sombra del titular vuelva a ser difusa (recortada dibujaba un rectángulo duro sobre el panal). - Borde facetado unificado: todo lo que lleva esquinas cortadas por
clip-path(tarjetas de plataforma, sellos de certificación, CTA fantasma) traza su borde con la misma técnica de dos capas recortadas — unbordernormal quedaría cercenado justo en la diagonal. - Teclado: las celdas de verticales son enfocables y revelan su descripción con
:focus-visibleigual que con hover; el menú móvil es un diálogo de verdad — al abrirse el foco entra al primer enlace, Tab circula en trampa entre el botón y los enlaces, y Escape cierra devolviendo el foco al botón; las flechas decorativas de los CTAs van enaria-hidden. - Táctil sin fantasmas: el halo que sigue al cursor ignora los
pointermovede tipotouch— sinpointerleavetáctil, se quedaba encendido para siempre en el último punto tocado. - La colmena puede fallar; la página no: todo el canvas vive en una función con guarda
(
try/catch+ comprobación del contexto 2D). Si el contexto no está disponible, el canvas se oculta y el menú, los revelados, los contadores y el scrollspy siguen intactos — un solo IIFE sin guarda habría muerto entero con él. - Sin JavaScript: un bloque
<noscript>muestra todo el contenido desde el primer pintado y los contadores traen su valor final en el HTML. - Scroll: un solo gesto grande (el zoom de la colmena) + revelados por sección con
IntersectionObservery retardos escalonados en variables CSS. prefers-reduced-motion: el canvas pinta un único fotograma estático a zoom medio (se repinta en scroll/resize, sin rAF), las gotas SMIL se ocultan, la cinta se detiene — y ya ni siquiera duplica su contenido, que solo servía al bucle — y los revelados aparecen sin transición. La página completa funciona sin JavaScript: el canvas es decorativo y las cifras traen su valor final en el HTML — el script las pone a cero y las cuenta solo cuando hay movimiento permitido, así nunca se enseña un dato falso.- Semántica: navegación real con menú móvil accesible (
aria-expanded), diagramas conrole="img"y descripciones, foco visible ámbar, contraste alto sobre cera. - Legibilidad y táctil: un scrim degradado protege el titular del canvas (y se disuelve al abrirse la colmena); skip-link al contenido; la cinta de certificaciones tiene alternativa sr-only y se pausa al hover; en pantallas táctiles las descripciones de las celdas de verticales se muestran siempre (nada depende del hover).
- Orientación: los eyebrows de sección van numerados 01/07…07/07 y la navegación marca la sección activa (scrollspy sin observers extra, resuelto en el mismo handler de scroll).
- Robustez (aprendido en la tercera pasada): el canvas vive tras una guarda — si el contexto 2D
no existe, se oculta y la orquestación de página (menú, revelados, contadores, cinta) sigue intacta.
El cambio de
prefers-reduced-motionen caliente se escucha conmatchMedia("change"): congela la colmena y limpia los pulsos al momento, o la arranca donde estaba. La cinta de certificaciones se duplica en potencias de 2 hasta cubrir dos pantallas — el bucletranslateX(-50%)exige mitades idénticas, y una sola duplicación dejaba hueco en viewports muy anchos. El menú móvil atrapa el foco (Tab circula entre botón y enlaces, Escape lo devuelve), todo el contenido cuelga de un landmark<main>, y el número de cada celda estadística se centra sobre su hexágono conaspect-ratio— no sobre la tarjeta entera, que lo hundía bajo el centro visual.
07 · DecisionesLo que se descartó
- WebGL: la estética de línea fina + relleno plano se resuelve mejor (y más nítida) en canvas 2D; el presupuesto de espectáculo se gastó en la orquestación, no en shaders porque sí.
- Imágenes generadas: ninguna. La colmena es 100% procedural — pesa menos, escala a cualquier densidad de píxel y nunca desentona con la paleta.
- Gradiente morado genérico y tipografías de sistema: prohibidos por principio; el ámbar único y Fraunces hacen el trabajo de marca.
- Mil micro-efectos: un gesto principal (zoom de colmena), tres gestos de apoyo (miel que llena, gotas que viajan, celdas que revelan). Nada más.