Volver al blog

Blog

Diseñar un sistema de diseño fuera de Figma

Design SystemsFigmaCursorTokensMonorepo

La idea central

Este proyecto nació de una pregunta que parece técnica, pero en realidad es una pregunta de producto: ¿qué pasa si el sistema de diseño no vive primero en una herramienta visual, sino en el mismo lugar donde se construye, se prueba y se consume el producto?

Cuando digo “diseñar un sistema de diseño fuera de Figma”, no me refiero a rechazar Figma. Figma sigue siendo una herramienta valiosa para explorar, alinear y comunicar. La diferencia está en la fuente de verdad. En este proyecto, la fuente de verdad dejó de ser un archivo visual y pasó a ser un sistema vivo en código: tokens, componentes, documentación, reglas, pruebas y automatizaciones.

Un token es una decisión de diseño convertida en una variable reutilizable. Por ejemplo: un color de fondo, un radio de borde, una sombra, un espacio entre elementos o una duración de animación. En vez de decidir esos valores una y otra vez en cada pantalla, el sistema los nombra, los centraliza y los reutiliza. Eso importa porque convierte el diseño en una infraestructura: algo que puede crecer, cambiar y mantenerse con menos improvisación.

Esa fue la intención de Design System Sho: pasar de una galería de componentes a un monorepo capaz de sostener un sistema de diseño real.

El punto de partida: una galería que servía como inventario

El repositorio empezó como una extracción inicial de un sistema de componentes. En esa primera etapa ya había una base importante: tokens, componentes, layouts y una app de documentación en Next.js. La galería era el lugar donde se podía ver lo que existía.

Ese primer showcase tenía un valor muy concreto: permitía inventariar. Antes de pensar en arquitectura avanzada, había que responder preguntas básicas:

  • ¿Qué componentes tenemos?
  • ¿Cómo se ven?
  • ¿Qué variantes existen?
  • ¿Qué partes son primitivas y cuáles son composiciones?
  • ¿Qué decisiones visuales se repiten?
  • ¿Qué está documentado y qué solo existe porque alguien lo recuerda?

La galería fue el primer puente entre intención y realidad. No era todavía un sistema maduro, pero sí era un espejo. Mostraba el estado del proyecto tal como era, con sus fortalezas y con sus huecos.

Ese aprendizaje fue importante: una galería de componentes no es solo una página bonita. Es una herramienta de auditoría. Sirve para descubrir inconsistencias, entender el inventario y empezar a tomar decisiones con evidencia.

El cambio de pregunta: de “¿cómo se ve?” a “¿cómo escala?”

Al principio, la pregunta principal era visual: que los componentes se vieran bien, que existiera una UI definida, que hubiera una identidad clara. Pero, a medida que el proyecto creció, la pregunta cambió.

La nueva pregunta fue: ¿cómo hacemos que esto escale?

Escalar no significa agregar más componentes sin orden. Escalar significa que el sistema pueda recibir nuevas piezas sin perder coherencia. Significa que una decisión de color no se copie manualmente en veinte archivos. Significa que el modo oscuro no dependa de excepciones componente por componente. Significa que los nombres sean claros, que las variantes sean predecibles y que cualquier persona pueda consumir el sistema desde otro proyecto.

Ese cambio de pregunta fue el punto de inflexión. El proyecto dejó de ser solo una colección visible y empezó a convertirse en una plataforma.

Decisión 1: token-first como principio de diseño

La primera gran decisión fue adoptar una lógica token-first.

Token-first significa que los componentes no deben inventar estilos por su cuenta. Un botón no debería decidir un azul específico. Una card no debería decidir una sombra aislada. Un input no debería tener un borde que solo vive dentro de ese archivo. Todo debe venir de tokens nombrados semánticamente.

En la práctica, eso llevó a una regla clara: usar variables --sho-* como base visual del sistema. Colores, espaciados, radios, tamaños, sombras, motion, layout y pesos tipográficos empezaron a organizarse como lenguaje común.

Esto importa por tres razones.

Primero, porque permite consistencia. Si el color de acción cambia, no se busca componente por componente. Se actualiza el token.

Segundo, porque permite temas. El modo oscuro no se resuelve con clases especiales por componente, sino redefiniendo los mismos tokens dentro de .dark. El componente usa el mismo nombre semántico; el tema decide el valor.

Tercero, porque permite gobernanza. Si el sistema tiene reglas claras, Cursor puede ayudar a implementarlas. La IA deja de improvisar estilos y empieza a trabajar dentro de un marco.

Aquí aparece una de las ideas más fuertes del proyecto: no basta con tener buen criterio. Hay que convertir ese criterio en reglas del repositorio.

Decisión 2: construir identidad propia, no copiar nomenclaturas externas

Otra decisión importante fue limpiar referencias externas y definir una nomenclatura propia para Sho.

Nombrar componentes parece un detalle menor, pero no lo es. Los nombres crean el mapa mental del sistema. Si un componente se llama de una forma en la documentación, de otra en el código y de otra en la conversación del equipo, el sistema empieza a perder claridad.

Por eso se definieron nombres canónicos. Algunos nombres heredados se reemplazaron por nombres más claros o más alineados con Sho: Snackbar pasó a Toast, Textfield a Input, BoxSelector a Choicebox, Message a Alert, FeedbackScreen a Result, entre otros.

El cambio no fue solo estético. Fue una decisión estratégica: el sistema necesitaba hablar con su propia voz.

Para que esa transición no fuera caótica, se documentó una guía de migración, se mantuvieron aliases de compatibilidad por un tiempo y se preparó un codemod. Un codemod es un script que ayuda a actualizar código automáticamente cuando hay cambios de API o nombres. En otras palabras, no solo se decidió cambiar nombres; se preparó el camino para que otros proyectos pudieran migrar.

Decisión 3: pasar del monolito a primitivos modulares

Durante una fase del proyecto, component-system.tsx concentró gran parte de la API pública. Eso tuvo valor en el momento: permitió reunir, ordenar y exponer componentes desde un lugar claro.

Pero un monolito también tiene límites. Cuando demasiadas decisiones viven en un solo archivo, el sistema se vuelve difícil de auditar, probar y extender.

La siguiente evolución fue mover las implementaciones reales a módulos por primitivo. Un primitivo es una pieza base: Button, Input, Modal, Table, Badge, Toast, Tabs, etc. Cada primitivo empezó a vivir en su propio folder, con sus variantes y su API.

Aquí aparece CVA, que significa Class Variance Authority. Es una librería que permite declarar variantes de componentes de forma ordenada. Por ejemplo, un botón puede tener variantes de jerarquía, tamaño, estado destructivo o loading. En vez de esparcir condiciones de estilos por todo el componente, CVA ayuda a definir esa matriz de variantes de manera explícita.

La decisión práctica fue esta: component-system.tsx dejó de ser el lugar donde vive todo y pasó a funcionar como un barrel, es decir, un archivo que reexporta componentes desde su fuente real.

Ese cambio hizo que el sistema se volviera más mantenible. Cada componente podía crecer sin contaminar a los demás. Y cada decisión de variante podía revisarse en su propio contexto.

Decisión 4: el layout también tenía que ser una fundación

Muchas veces, los sistemas de diseño se concentran en color, tipografía y componentes, pero dejan el layout a decisiones locales. Este proyecto tomó otro camino.

Se definió una fundación de layout basada en una mini unidad de 8 px, columnas fluidas por breakpoint y primitivas como Grid, GridColumn, Stack, Cluster y PageShell.

Esto importa porque el layout es donde muchas interfaces se rompen. Un componente puede estar bien diseñado de forma aislada, pero si cada pantalla usa gaps, columnas, márgenes y contenedores distintos, el producto completo se siente inconsistente.

La decisión de layout 2x fue convertir la geometría del producto en parte del sistema. No solo diseñar botones, sino también diseñar el espacio donde esos botones viven.

Decisión 5: la documentación pasó de galería a producto

La app de docs evolucionó mucho. Al inicio era una galería. Después empezó a comportarse como un producto interno.

Aparecieron una home de marketing, navegación por foundations y components, un playbook de escenarios reales, búsqueda con command palette y previews con toggle de modo oscuro. También se separaron los showcases en archivos lazy-loaded para que el sistema no dependiera de un único archivo gigante.

Este cambio es importante porque la documentación de un design system no solo explica el sistema. También lo prueba.

Un componente aislado puede verse bien. Pero el playbook hace otra pregunta: ¿cómo se comporta cuando se combina con otros componentes en flujos reales? Formularios, checkout, scheduling, feedback, tablas, filtros, estados vacíos. Ese tipo de documentación acerca el sistema a la realidad del producto.

En ese sentido, la documentación se convirtió en una segunda capa de validación. No solo mostraba componentes. Mostraba decisiones funcionando juntas.

Decisión 6: gobernanza automatizada

La palabra gobernanza puede sonar pesada, pero la idea es simple: ¿cómo evitamos que el sistema se degrade con el tiempo?

Un design system se degrada cuando las reglas viven solo en la memoria de una persona. Se degrada cuando alguien agrega un color directo porque tenía prisa. Se degrada cuando un componente nuevo no respeta los tokens. Se degrada cuando el modo oscuro se resuelve con parches por archivo. Se degrada cuando no hay forma rápida de saber si una decisión rompió otra.

Para evitar eso, el proyecto incorporó varias capas de control:

  • Reglas de Cursor para trabajar con tokens Sho.
  • Una skill interna para construir componentes siguiendo el checklist del sistema.
  • Scripts de verificación para tokens, estilos y layout.
  • ESLint personalizado para bloquear estilos no permitidos.
  • Dependency Cruiser para cuidar límites entre capas.
  • Typecheck, lint, tests, smoke tests y CI.

La idea clave es que el sistema no dependa solo de revisión manual. La revisión humana sigue siendo importante, pero ahora está acompañada por herramientas que detectan desviaciones.

Este es uno de los aprendizajes centrales del proyecto: si vas a usar IA para construir un sistema de diseño, necesitas darle reglas verificables. Cursor fue potente no porque reemplazara el criterio, sino porque pudo trabajar dentro de un marco que yo fui definiendo.

Decisión 7: migrar a monorepo

El paso a monorepo fue una de las decisiones más importantes.

Un monorepo es un repositorio que contiene varios paquetes o aplicaciones relacionados. En este caso, el proyecto pasó a organizarse con apps/ y packages/:

  • @sho/react para los componentes, primitivas y layouts.
  • @sho/styles para tokens y CSS publicable.
  • @sho/docs para la documentación y showcase.
  • @sho/playground para probar consumo aislado.
  • Paquetes de tooling como @sho/codemod, @sho/eslint-config y @sho/tsconfig.

Esta estructura importa porque separa responsabilidades. La documentación ya no es lo mismo que la librería. Los estilos ya no están mezclados con la app. Los componentes pueden construirse, versionarse y consumirse como paquete.

El monorepo fue el paso que convirtió el proyecto en algo más cercano a una infraestructura reutilizable. Ya no era solo “un repo donde se ven componentes”. Era una base para que otros proyectos pudieran consumir Sho.

La tensión de la migración: conservar la UI sin perder la nueva estructura

Una de las conversaciones más importantes ocurrió después de la migración a monorepo. La estructura nueva era más limpia, pero algunos componentes ya no se veían como antes. Había estilos cambiados, partes rotas y falta de color.

Ese momento fue clave porque reveló una tensión real en cualquier migración: una buena arquitectura no sirve si pierde la experiencia visual que ya estaba conseguida.

El objetivo no era volver atrás. El objetivo era recuperar la UI definida antes de la migración, pero manteniendo la estructura nueva.

Ese aprendizaje es muy importante para compartir: la arquitectura debe proteger el diseño, no reemplazarlo. Una migración exitosa no es la que solo deja carpetas más limpias. Es la que conserva el comportamiento y la apariencia que ya funcionaban, mientras mejora la capacidad de mantenimiento.

Ese tipo de decisión es exactamente donde el modo plan de Cursor fue útil. Antes de editar, había que entender qué había pasado: imports, tokens, CSS modularizado, detección de Tailwind, dist de paquetes, rutas antiguas, servidor stale, componentes que apuntaban a paths previos. El trabajo no era “arreglar colores”; era diagnosticar el sistema.

Theme Studio: cerrar el loop visual dentro del mismo sistema

Otro hito importante fue Theme Studio.

Theme Studio lleva una idea poderosa al proyecto: si los tokens son la fuente de verdad, también debería existir una forma visual de editarlos, probarlos y exportarlos dentro del mismo entorno donde vive el sistema.

Esto acerca el proyecto a una alternativa real a Figma Variables para ciertos flujos. No porque replique todo Figma, sino porque permite iterar temas visualmente en el browser y conectar esa iteración con los tokens que realmente consume la app.

La promesa es clara: ver, ajustar, probar y exportar sin romper la cadena entre diseño y desarrollo.

El papel de Cursor: no magia, sino amplificación del criterio

Cursor fue una herramienta central en este proceso, pero no como reemplazo de experiencia.

La IA acelera cuando hay dirección. Sin dirección, puede producir código que funciona en apariencia, pero que rompe el sistema. Con reglas claras, puede convertirse en una extensión del criterio del equipo.

En este proyecto, el modo plan tuvo un rol estratégico. Sirvió para pensar antes de tocar código, separar síntomas de causas, discutir tradeoffs y convertir una intención amplia en pasos concretos.

La experiencia previa también fue clave. Saber qué pedir, qué revisar, qué bloquear, qué aceptar y qué convertir en regla es parte del trabajo. Cursor ayudó a ejecutar, explorar, auditar y migrar. Pero las decisiones importantes siguieron siendo decisiones de producto y sistema.

La frase que resume esto es: no usé Cursor para que decidiera por mí; lo usé para multiplicar mi capacidad de convertir decisiones en estructura.

Lo que realmente se construyó

Visto desde fuera, el resultado podría resumirse como un monorepo con React, tokens y docs. Pero eso se queda corto.

Lo que se construyó fue una forma de trabajar:

  • Un sistema token-first donde el diseño vive como variables, no como valores sueltos.
  • Un set de primitivas modulares con variantes explícitas.
  • Una nomenclatura propia para Sho.
  • Una documentación que funciona como inventario, prueba y producto interno.
  • Una fundación de layout para ordenar el espacio, no solo los componentes.
  • Un Theme Studio para iterar visualmente con tokens reales.
  • Un monorepo preparado para consumo desde otros proyectos.
  • Una capa de gobernanza para que humanos y agentes trabajen con las mismas reglas.

También hubo escala concreta: alrededor de 26 commits en una etapa intensa, más de 500 archivos tocados, cerca de 42 primitivas modulares, una matriz de 45 componentes, variantes P0-P2, renombres canónicos, mejoras de accesibilidad WCAG 2.2 AA, CI, pruebas y empaquetado @sho/*.

Esos números importan no por volumen, sino porque muestran que el trabajo dejó de ser una maqueta. Pasó a ser una plataforma.

Aprendizajes para la audiencia

El primer aprendizaje es que un sistema de diseño no empieza cuando todo está perfecto. Empieza cuando decides hacer visible lo que existe. La galería fue ese primer acto de honestidad.

El segundo aprendizaje es que los tokens son más que variables. Son decisiones. Cuando un equipo nombra bien sus tokens, está nombrando su forma de pensar.

El tercer aprendizaje es que la arquitectura no debe ir en contra de la UI. Si una migración rompe lo que ya funcionaba, hay que corregir la migración, no sacrificar la experiencia.

El cuarto aprendizaje es que documentar no es escribir después. Documentar puede ser una forma de diseñar. El showcase, el playbook y las matrices de variantes ayudaron a decidir, no solo a explicar.

El quinto aprendizaje es que la IA necesita gobierno. Cursor fue útil porque el proyecto tenía reglas, skills, verificaciones y una visión clara. La IA no elimina la necesidad de criterio; la vuelve más urgente.

El sexto aprendizaje es que Figma no tiene que ser el único centro del sistema. Para muchos equipos, el código puede ser la fuente de verdad cuando el objetivo es que el sistema sea consumible, verificable y versionable.

La historia en una frase

Design System Sho pasó de ser una galería de componentes a convertirse en un sistema de diseño en código: token-first, modular, documentado, verificable y preparado para otros proyectos.

La historia no es solo “hicimos un monorepo”. La historia es que el diseño empezó a vivir donde también vive la ejecución. Y gracias a Cursor, al modo plan y a la experiencia acumulada, ese trabajo pudo avanzar con velocidad sin perder intención.

Cierre posible para la presentación

Si tuviera que cerrar esta historia frente a una audiencia, diría esto:

No estaba intentando sacar Figma de la conversación. Estaba intentando demostrar que un sistema de diseño puede tener otra fuente de verdad.

Figma ayuda a imaginar. Pero este proyecto necesitaba algo más: necesitaba reglas, paquetes, tokens, pruebas, documentación, migraciones y consumo real.

La galería fue el primer espejo. Los tokens fueron el lenguaje. Los componentes fueron la materia prima. El monorepo fue la infraestructura. Cursor fue el copiloto. Y el modo plan fue el espacio donde las decisiones dejaron de ser intuiciones sueltas y se convirtieron en estrategia.

Eso es lo que he construido con Design System Sho: no solo una colección de componentes, sino una manera de convertir criterio de diseño en sistema.

Fuentes internas revisadas

  • README.md
  • CHANGELOG.md
  • CONTRIBUTING.md
  • docs/architecture.md
  • docs/MIGRATION.md
  • docs/component-checklist.md
  • docs/component-variants-roadmap.md
  • docs/component-variants-audit-report.md
  • docs/layout-foundation.md
  • .cursor/rules/token-first-components.mdc
  • .cursor/skills/build-sho-component/SKILL.md
  • Historial de commits del repositorio
  • Transcripciones previas de trabajo, incluyendo resumen de las últimas dos semanas y plan de recuperación visual después de la migración a monorepo