Vercel: Experiencia de Desarrollador como Diseño

Cómo Vercel hizo de la experiencia del desarrollador el producto: diseño dark-mode-first, indicadores de estado en pestañas, UI optimista y estados vacíos funcionales. Con patrones de implementación CSS y JavaScript.

6 min de lectura 1256 palabras
Vercel: Experiencia de Desarrollador como Diseño screenshot

Vercel: La experiencia del desarrollador como diseño

«Los desarrolladores son alérgicos a la mala UX — no quieren un "onboarding encantador" si los ralentiza.»

La filosofía de diseño de Vercel es implacablemente centrada en el desarrollador. El sistema de diseño Geist prioriza la claridad, la velocidad y la densidad de información por encima de la decoración. Cada píxel está al servicio del flujo de trabajo del desarrollador.


Por qué Vercel importa

Vercel demuestra que las herramientas para desarrolladores pueden tener un diseño excepcional sin ser "diseñosas". El dashboard es rápido, denso en información y no se interpone en el camino.

Logros clave: - Creó Geist, una tipografía diseñada específicamente para desarrolladores - El rediseño del dashboard redujo el First Meaningful Paint en 1.2s - Fue pionero en el diseño dark-mode-first en herramientas para desarrolladores - Estableció el estándar para la UX de despliegue - Iconos de pestaña que reflejan el estado del despliegue (compilando, error, listo)


Conclusiones clave

  1. El modo oscuro es respeto, no una funcionalidad - Los desarrolladores trabajan en terminales e IDEs con fondos oscuros; un dashboard blanco genera cambios de contexto bruscos y fatiga visual
  2. El estado debe estar visible en todas partes - Favicons en pestañas, títulos de página, puntos en la línea de tiempo: el estado del despliegue debería ser visible sin cambiar de foco ni abrir pestañas
  3. La UI optimista elimina la latencia percibida - Muestra el estado esperado de inmediato, sincroniza con la realidad en segundo plano; los desarrolladores notan retrasos de 300ms
  4. Los estados vacíos son instrucciones, no ilustraciones - Muestra el comando exacto a ejecutar (git push origin main), no un gráfico decorativo con un botón de "Comenzar"
  5. El rendimiento es diseño - El rediseño del dashboard de Vercel redujo el First Meaningful Paint en 1.2s; ninguna cantidad de animaciones bonitas compensa tiempos de carga lentos

Filosofía de diseño fundamental

El principio centrado en el desarrollador

Los desarrolladores juzgan los productos por lo poco que los ralentizan. El diseño de Vercel refleja esto:

ANTI-PATRONES (Lo que los desarrolladores odian)    ENFOQUE DE VERCEL
───────────────────────────────────────────────────────────────────
Animaciones "encantadoras" que añaden retraso     Estados instantáneos, sin transiciones
Wizards de onboarding que bloquean el trabajo     CLI-first, dashboard opcional
Documentación densa oculta en pestañas            Información visible de un vistazo
Spinners de carga en cada acción                  Actualizaciones optimistas + SWR
Texto de marketing en el dashboard                UI puramente funcional

Idea clave: Los desarrolladores no quieren ser "deleitados". Quieren desplegar.


Biblioteca de patrones

1. Excelencia en modo oscuro

El modo oscuro de Vercel no es un toggle. Es el valor por defecto. El diseño es quirúrgico: blanco y negro puros crean el máximo contraste.

Filosofía de color:

:root {
  /* La paleta de Vercel es notablemente simple */

  /* Fondos - negro puro, sin grises */
  --bg-000: #000000;
  --bg-100: #0A0A0A;
  --bg-200: #111111;

  /* Primer plano - blanco de alto contraste */
  --fg-100: #FFFFFF;
  --fg-200: #EDEDED;
  --fg-300: #A1A1A1;
  --fg-400: #888888;

  /* Bordes - sutiles pero visibles */
  --border-100: #333333;
  --border-200: #444444;

  /* Semánticos - estado de despliegue */
  --color-success: #00DC82;  /* Verde - desplegado */
  --color-error: #FF0000;    /* Rojo - fallido */
  --color-warning: #FFAA00;  /* Ámbar - compilando */
  --color-info: #0070F3;     /* Azul - en cola */

  /* El acento - la firma de Vercel */
  --accent: #FFFFFF;         /* Blanco como acento sobre negro */
}

Por qué funciona el negro puro: - Máximo contraste para la legibilidad del texto - Estética inspirada en la terminal que los desarrolladores reconocen - Reduce la fatiga visual en entornos oscuros - Hace que los indicadores de estado con color destaquen


2. Indicadores de estado en pestañas

Vercel refleja el estado del despliegue en los iconos de las pestañas del navegador, haciendo visible la información incluso cuando la pestaña no está en primer plano.

┌─ Barra de pestañas del navegador ──────────────────────────────────┐
│                                                                    │
│  [▶] acme-web - Compilando  [✓] blog - Listo    [✕] api - Error   │
│                                                                    │
└────────────────────────────────────────────────────────────────────┘

Estados del icono de pestaña:
  ⏳ En cola (círculo gris)
  ▶  Compilando (spinner animado)
  ✓  Listo (check verde)
  ✕  Error (X roja)

Patrón de implementación:

// Favicon dinámico basado en el estado del despliegue
function updateFavicon(status) {
  const link = document.querySelector("link[rel~='icon']");

  const icons = {
    queued: '/favicon-queued.svg',
    building: '/favicon-building.svg',  // Animado
    ready: '/favicon-ready.svg',
    error: '/favicon-error.svg',
  };

  link.href = icons[status];
}

// El título también refleja el estado
function updateTitle(projectName, status) {
  const prefixes = {
    queued: '⏳',
    building: '▶',
    ready: '✓',
    error: '✕',
  };

  document.title = `${prefixes[status]} ${projectName} - Vercel`;
}

Idea clave: Los desarrolladores tienen muchas pestañas abiertas. El estado visible en la barra de pestañas significa que no necesitan cambiar de pestaña para verificar el estado de la compilación.


3. Línea de tiempo de despliegue

El inspector de despliegue muestra una línea de tiempo clara del proceso de despliegue.

┌─ Línea de tiempo de despliegue ────────────────────────────────────┐
│                                                                    │
│  [o] En cola                                 12:34:56 PM           │
│  │                                                                 │
│  [o] Compilando                              12:34:58 PM           │
│  │ └─ Instalando dependencias... 3.2s                              │
│  │ └─ Compilando... 12.4s                                          │
│  │ └─ Generando páginas estáticas... 2.1s                          │
│  │                                                                 │
│  [o] Desplegando                             12:35:14 PM           │
│  │ └─ Subiendo artefactos de compilación...                        │
│  │                                                                 │
│  [*] Listo                                   12:35:18 PM           │
│    └─ https://acme-abc123.vercel.app                               │
│                                                                    │
│  Total: 22s                                                        │
│                                                                    │
└────────────────────────────────────────────────────────────────────┘

Codificación visual:

.timeline-step {
  position: relative;
  padding-left: 24px;
}

.timeline-step::before {
  content: '';
  position: absolute;
  left: 0;
  top: 6px;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--step-color);
}

/* Línea de conexión */
.timeline-step:not(:last-child)::after {
  content: '';
  position: absolute;
  left: 4px;
  top: 16px;
  width: 2px;
  height: calc(100% - 6px);
  background: var(--border-100);
}

/* Estados de los pasos */
.timeline-step[data-status="complete"]::before {
  background: var(--color-success);
}

.timeline-step[data-status="active"]::before {
  background: var(--color-warning);
  animation: pulse 1.5s infinite;
}

.timeline-step[data-status="error"]::before {
  background: var(--color-error);
}

.timeline-step[data-status="pending"]::before {
  background: var(--fg-400);
}

4. Diseño del Visor de Logs

El visor de logs de Vercel está integrado en la vista general del despliegue, no en una página separada.

┌─ Build Logs ───────────────────────────────────────────────────────┐
│                                                                    │
│  Filter: [All ▼]  [Function: api/hello ▼]           [Copy] [↓]    │
│                                                                    │
├────────────────────────────────────────────────────────────────────┤
│                                                                    │
│  12:34:58.123  info   Installing dependencies...                   │
│  12:35:01.456  info   added 1234 packages in 3.2s                  │
│  12:35:01.789  info   Running build...                             │
│  12:35:14.012  info   ✓ Compiled successfully                      │
│  12:35:14.234  warn   Large bundle size: pages/index.js (245kb)    │
│  12:35:14.567  info   Generating static pages...                   │
│  12:35:16.890  info   ✓ Generated 42 pages                         │
│                                                                    │
└────────────────────────────────────────────────────────────────────┘

Características clave: - Copia al portapapeles con un solo clic - Filtrado por función o salida de compilación - Niveles de log con código de colores (info, warn, error) - Marcas de tiempo con precisión de milisegundos - URLs compartibles para líneas de log específicas

Implementación:

.log-line {
  display: flex;
  font-family: var(--font-mono);
  font-size: 12px;
  line-height: 1.6;
  padding: 2px 12px;
}

.log-line:hover {
  background: var(--bg-200);
}

.log-timestamp {
  color: var(--fg-400);
  min-width: 100px;
  margin-right: 12px;
}

.log-level {
  min-width: 48px;
  margin-right: 12px;
}

.log-level[data-level="info"] { color: var(--fg-300); }
.log-level[data-level="warn"] { color: var(--color-warning); }
.log-level[data-level="error"] { color: var(--color-error); }

.log-message {
  color: var(--fg-100);
  white-space: pre-wrap;
  word-break: break-word;
}

5. Estados Vacíos

Los estados vacíos de Vercel son funcionales, no decorativos. Te indican qué hacer a continuación.

┌─ Empty State: No Deployments ──────────────────────────────────────┐
│                                                                    │
│                                                                    │
│                         No deployments yet                         │
│                                                                    │
│               Push to your repository to create                    │
│                    your first deployment                           │
│                                                                    │
│                                                                    │
│           git push origin main                                     │
│                                                                    │
│                                                                    │
│                         [View Documentation]                       │
│                                                                    │
│                                                                    │
└────────────────────────────────────────────────────────────────────┘

Principios de diseño: - Sin ilustraciones decorativas - Acción clara (el comando git) - Enlace útil a la documentación - Monoespaciado para comandos (fácil de copiar)


Sistema de Diseño Visual

Tipografía (Geist)

Vercel creó Geist específicamente para experiencias de desarrollador:

:root {
  /* Geist Sans - UI and body text */
  --font-sans: 'Geist', -apple-system, BlinkMacSystemFont, sans-serif;

  /* Geist Mono - code and technical content */
  --font-mono: 'Geist Mono', 'SF Mono', monospace;

  /* Size scale */
  --text-xs: 12px;
  --text-sm: 13px;
  --text-base: 14px;
  --text-lg: 16px;
  --text-xl: 18px;
  --text-2xl: 24px;

  /* Line heights */
  --leading-tight: 1.25;
  --leading-normal: 1.5;
  --leading-relaxed: 1.75;

  /* Letter spacing */
  --tracking-tight: -0.02em;
  --tracking-normal: 0;
  --tracking-wide: 0.02em;
}

/* Tabular numbers for data */
.tabular-nums {
  font-variant-numeric: tabular-nums;
}

/* Or use Geist Mono for comparisons */
.data-value {
  font-family: var(--font-mono);
}

Sistema de Espaciado

:root {
  /* 4px base unit */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 20px;
  --space-6: 24px;
  --space-8: 32px;
  --space-10: 40px;
  --space-12: 48px;
  --space-16: 64px;
}

Border Radius

:root {
  /* Radios sutiles y consistentes */
  --radius-sm: 4px;
  --radius-md: 6px;
  --radius-lg: 8px;
  --radius-xl: 12px;
  --radius-full: 9999px;
}

Patrones de Animación

Actualizaciones Optimistas

Vercel utiliza actualizaciones de interfaz optimistas. Las acciones se sienten instantáneas.

// Patrón SWR para actualizaciones en tiempo real
const { data, mutate } = useSWR('/api/deployments');

async function triggerDeploy() {
  // Mostrar inmediatamente el estado "desplegando"
  mutate(
    { ...data, status: 'building' },
    false  // No revalidar todavía
  );

  // Luego ejecutar realmente
  await fetch('/api/deploy', { method: 'POST' });

  // Revalidar para obtener el estado real
  mutate();
}

Estados de Carga Sutiles

/* Carga skeleton - sin spinners */
.skeleton {
  background: linear-gradient(
    90deg,
    var(--bg-200) 0%,
    var(--bg-100) 50%,
    var(--bg-200) 100%
  );
  background-size: 200% 100%;
  animation: shimmer 1.5s infinite;
  border-radius: var(--radius-md);
}

@keyframes shimmer {
  0% { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

Estados de Botones

.button {
  transition: background 100ms ease, transform 100ms ease;
}

.button:hover {
  background: var(--fg-100);
}

.button:active {
  transform: scale(0.98);
}

/* Sin transiciones largas - retroalimentación instantánea */

Optimizaciones de Rendimiento (Informadas por el Diseño)

El rediseño del dashboard de Vercel incluyó decisiones de diseño que mejoraron el rendimiento:

Técnicas utilizadas: - Preconexión a los orígenes de API, Assets y Avatar - Las llamadas críticas a la API reciben mayor prioridad del navegador - Memoización de componentes React (useMemo, useCallback) - ReactDOM.unstable_batchedUpdates redujo los re-renders en un 20% - SWR para actualizaciones eficientes de datos en tiempo real

Idea clave: El rendimiento ES diseño. Un dashboard lento con animaciones hermosas es peor que un dashboard rápido sin ninguna.


Lecciones para Nuestro Trabajo

1. Modo Oscuro como Predeterminado

Cuando tus usuarios trabajan en entornos oscuros (terminales, IDEs), el modo oscuro no es una funcionalidad—es respeto.

2. Estado en Cada Rincón

Iconos de pestaña, títulos de página, indicadores de línea de tiempo: el estado debe ser visible sin necesidad de enfocar la atención.

3. Optimista por Defecto

Muestra el estado esperado de inmediato. Actualiza con la realidad en segundo plano.

4. Los Desarrolladores Odian Esperar

Nada de spinners de carga si puedes evitarlos. Estados skeleton, actualizaciones optimistas, precarga.

5. Los Estados Vacíos Son Instrucciones

No muestres una ilustración bonita. Muestra el comando que necesitan ejecutar.


Preguntas Frecuentes

¿Por qué Vercel usa negro puro (#000000) en lugar de gris oscuro para los fondos?

El negro puro proporciona el máximo contraste para el texto blanco, creando una legibilidad óptima. También coincide con la estética de las terminales y editores de código que los desarrolladores ya utilizan, haciendo que el dashboard se sienta como una parte nativa de su flujo de trabajo. Los fondos en gris oscuro suelen parecer más "suaves" pero reducen el contraste y pueden verse deslavados en pantallas de alta resolución.

¿Cómo funcionan los indicadores de estado en las pestañas de Vercel?

Vercel actualiza dinámicamente el favicon del navegador según el estado del despliegue: un spinner durante la compilación, una marca verde cuando está listo, una X roja en caso de error. El título de la página también se actualiza con prefijos de emoji (▶, ✓, ✕). Esto significa que los desarrolladores pueden monitorear múltiples despliegues en distintas pestañas sin cambiar el foco—el estado es visible de un vistazo en la barra de pestañas del navegador.

¿Cuál es el enfoque de Vercel respecto a los estados de carga?

Vercel evita los spinners de carga tradicionales en favor de la interfaz optimista y las pantallas skeleton. Cuando activas un despliegue, la interfaz muestra inmediatamente el estado "compilando" antes de que el servidor confirme. La biblioteca SWR se encarga de la revalidación en segundo plano. Esto hace que las acciones se sientan instantáneas incluso cuando las solicitudes de red tardan entre 200 y 500ms.

¿Qué es Geist y por qué Vercel creó una tipografía personalizada?

Geist es una familia tipográfica que Vercel diseñó específicamente para interfaces de desarrollo. Incluye Geist Sans para texto de interfaz y Geist Mono para código. El diseño está optimizado para tamaños pequeños (12-14px) comunes en dashboards, incluye números tabulares para columnas de datos alineadas y tiene formas de caracteres diferenciadas para evitar confusión entre glifos similares (l, 1, I).

¿Cómo maneja Vercel los estados vacíos de forma diferente a otros productos?

Los estados vacíos de Vercel muestran comandos accionables, no ilustraciones decorativas. Una página de despliegues vacía muestra git push origin main en tipografía monoespaciada (facilitando el copiado) en lugar de una caricatura con un botón genérico de "Comenzar". La filosofía es que los desarrolladores quieren saber exactamente qué hacer, no ser calmados visualmente.