Guía de diseño y técnica · CyberSenseAI

Cómo se hizo «El parqué de las Personas IA»

Una homepage de banca clásica para un producto radicalmente nuevo: la metáfora del parqué bursátil aplicada a AICREI Enterprise. Todo procedural, un solo archivo, sin librerías: canvas con proyección 3D a mano, odómetros mecánicos y cinta de cotización continua.

← Volver al parqué

01 · El concepto

Un mercado donde el activo es el talento.

CyberSenseAI vende algo insólito: Personas IA que se incorporan a un equipo como un miembro más. La metáfora bursátil lo traduce a un lenguaje que un CTO, un CISO o un consejo de administración entienden de forma instintiva: activos que cotizan, resultados que se auditan, una casa que se regula.

02 · Paleta y tipografía

Verde bosque, latón y papel de cotización.

--tinta#10291e
--bosque-2#0b2018
--laton#b48a3c
--laton-2#d8ab5a
--crema#f4ecdc
--alza#2f7d4f
--baja#a4432f

El crema domina como papel de fondo; el verde bosque profundo se reserva para los «tablones» (hero, XAIOS, CREI, cierre); el latón es el único metal — acentos, itálicas y botones. El rojo teja aparece una sola vez con intención: el sello de caucho «Admitida a cotización».

Bodoni Moda — la didona del membrete

Display · titulares, códigos de corro, iniciales CREI

IBM PLEX MONO — LA CINTA DEL TELETIPO · 171,30 ▲

Texto, datos, navegación, odómetros, cinta

Par deliberadamente polar: la didona aporta la solemnidad del grabado bancario del XIX; la mono, el pulso mecánico del teletipo. No hay tercera familia — la tensión entre ambas es el sistema.

La textura se genera con un feTurbulence SVG embebido como data-URI, fijado a pantalla completa con mix-blend-mode: multiply al 7% — grano de papel constante sin pesar un solo byte de imagen. Las secciones claras añaden un rayado de libro mayor con repeating-linear-gradient.

03 · La ciudad de velas

Proyección 3D a mano sobre canvas 2D.

Sin WebGL, sin librerías: 360 velas (30×12) viven en un mundo 3D propio y se proyectan a 2D con una cámara en perspectiva de un punto. Cada vela hace un paseo aleatorio con deriva alcista — la ciudad crece, como el índice.

La campana de apertura: al cargar, la ciudad no existe. Cada vela tiene una hora de nacimiento (birth, escalonada por fila y distancia al eje) y se levanta desde el suelo en una oleada de ~2,5 s; las mechas crecen con el cuerpo para que nada flote antes de nacer. Mientras tanto, la cifra del tablón cuenta de 100,00 a 171,30 — y a partir de ahí el índice ES la ciudad: la lectura de cabecera se liga a la media real de las velas en pantalla, con la misma deriva alcista contenida.

// cámara: foco fijo, deriva senoidal + parallax de puntero
function project(x, y, z){
  var s = FOCAL / z;
  return { x: W*.5 + (x - camX)*s, y: H*.33 + (camY - y)*s, s: s };
}

// cada vela: cuerpo 3D (frente + tapa + lado visible) y mecha
var fTL = project(c.x - hw, c.h, zF), fBR = project(c.x + hw, 0, zF);
var bTL = project(c.x - hw, c.h, zB), bTR = project(c.x + hw, c.h, zB);
ctx.fillStyle = shade(F, fog);          // niebla: lerp hacia el fondo
ctx.fillRect(fTL.x, fTL.y, fBR.x - fTL.x, fBR.y - fTL.y);

04 · Odómetros mecánicos

Cifras que ruedan como un contador de latón.

Cada dígito es una rueda física: una tira vertical de dígitos 0–9 repetidos N vueltas dentro de una ventana con sombras internas de tambor. Al entrar en viewport, cada rueda recibe su destino como variable CSS y la transición hace el resto — cuanto más a la derecha la rueda, más vueltas da y más tarda en asentarse.

var spins = 2 + reels.length;          // cada rueda gira más que la anterior
var target = spins * 10 + (+ch);       // p. ej. «7» → 47 posiciones
r.strip.style.setProperty('--t', (1.7 + i*.45) + 's');
r.strip.style.setProperty('--n', r.target);

/* CSS: la tira baja n·altura-de-dígito con curva de asentamiento */
.odo-strip{ transform: translateY(calc(var(--n,0) * var(--dh) * -1)) }
.odo.armed .odo-strip{ transition: transform var(--t) cubic-bezier(.14,.84,.16,1) }

Los símbolos (−, ×, /, %) son separadores estáticos: solo los dígitos ruedan, como en un contador real. Sin JS los valores aparecen impresos en texto plano; con prefers-reduced-motion, las ruedas saltan directamente a su posición.

05 · La cinta y el resto del atrezo

Teletipo continuo, ticket perforado, bóveda giratoria.

06 · Decisiones y verificación

Reglas de la casa.

DecisiónPor qué
Cero imágenesTodo es procedural: canvas, SVG y CSS. La página pesa lo que pesa su tipografía.
Un solo archivoCSS y JS inline; la única dependencia externa es Google Fonts.
ES5, sin transpiladoresFunciona en cualquier navegador razonable; con JS apagado, todo el contenido sigue legible.
Reduced motion dignoCinta estática envolvente, ciudad congelada, ruedas en destino, reveals visibles. Nada desaparece.
Datos etiquetadosToda cotización simulada lo declara («cotización simulada»); las cifras reales — 40%, ×10, 24/7, 171% — son las del producto.
Verificación realHeadless Chrome + Playwright: cero errores de consola, cero scroll horizontal a 1440 y 390 px, odómetros y cintas comprobados en DOM renderizado.
Tintas AA (pasada 2)Dos tokens de texto — --laton-ink #7a5a22 y --alza-ink #23663f — sustituyen a latón y verde alza en toda microtipografía sobre crema; las cremas translúcidas sobre bosque suben a α ≥ .62. Todo texto pequeño cumple 4,5:1; latón y alza originales quedan para display y elementos gráficos.
Foco = hover (pasada 2)El subrayado de la navegación responde también a :focus-visible; los botones fantasma tienen estado :active; la flecha del índice tiene estilo propio también a la baja (.board-read .dn).
Coherencia de datos (pasada 2)El índice del tablón se acota a 158–184 para no contradecir al libro de órdenes (~171); los 8 criterios del comité revelan en cascada (60 ms por asiento) con el mismo easing de la casa.
Craft fino (pasada 3)Subrayado de navegación por transform: scaleX (sale por donde entró, sin relayout); border-color incluido en la transición de botones; sellos y marca con hover propio; el libro de órdenes «imprime» cada actualización con un fundido de 500 ms en vez de saltar; regla entre columnas del examen del comité; contrastes de microetiquetas (cabeceras del libro, códigos de corro, numeración de puestos) subidos a AA.
Accesibilidad de odómetros (pasada 3)Cada odómetro recibe role="img" al montar las ruedas: el lector de pantalla anuncia el aria-label («40 por ciento de reducción…») y nunca los 20–40 dígitos internos de las tiras.
Datos estructurados (pasada 3)JSON-LD Organization en el <head> (nombre, URL, eslogan, productos) completa el bloque de metadatos junto a OG/Twitter y el favicon SVG.
Robustez (pasada 3)Si getContext('2d') devuelve null (contextos agotados, render por software), cada canvas se rinde en silencio y el resto de la página sigue íntegro. Las cintas se reconstruyen al cambiar el ancho de ventana (rotación incluida): sin huecos en el bucle infinito. El libro de órdenes solo trabaja si está en viewport y la pestaña visible.
Táctil sin bandazos (pasada 3)El parallax de cámara del tablón solo se activa con pointer: fine: en móvil el arrastre del scroll ya no zarandea la ciudad. La cabecera de la tabla de corros se realinea a su rejilla de 3 columnas en ≤640 px.
Campana coherente (pasada 3)El índice se fija en «100,00» en el instante en que arranca la sesión — sin destello del valor final antes de la cuenta — y el «calor de mercado» que enciende el horizonte enciende también la línea discontinua del índice: un solo pulso para todo el tablón.