yesid.dev-design: una base visual compartida
Una base visual común, espacio para cada producto
Un botón, un título y una pequeña respuesta al hacer clic pueden hacer que varios productos se sientan parte de la misma familia. Mantener esa coherencia requiere más cuidado cuando cada producto tiene su contenido, su comportamiento y su propio calendario de actualizaciones.
Creé yesid.dev-design para darles una base común a mis proyectos y dejar claras sus diferencias. Reúne las reglas visuales, los controles reutilizables y los comportamientos de interacción de la marca yesid. Transit y yesid.dev han adoptado versiones de esta base. Una galería de componentes permite ver cómo funcionan las piezas compartidas.
Es un proyecto de infraestructura en desarrollo, con código, versiones y responsabilidades propias. Su propósito es facilitar el mantenimiento de las decisiones comunes y la revisión de los cambios.
El proyecto en breve#
El problema#
Varios productos necesitan verse relacionados sin heredar las decisiones particulares de los demás. Mantener las mismas reglas visuales en lugares separados dificulta saber si una diferencia es intencional o si las copias se han ido apartando.
Qué construí#
Una base compartida para los valores de diseño, los controles reutilizables y el movimiento, con una galería que permite ver su comportamiento. También incluye mecanismos comunes de verificación de calidad, metadatos para buscadores, analítica y enrutamiento por idioma. Cada parte tiene una responsabilidad definida y un proceso de versiones revisado.
A qué productos les sirve#
Transit y yesid.dev han adoptado esta base. Conservan sus páginas, contenido, datos y decisiones de ejecución. La galería interna ofrece ejemplos neutros para revisar el comportamiento compartido antes de que cada producto verifique su propio uso.
La principal decisión#
Compartir más código también conecta más decisiones. Transit requiere tarjetas planas; yesid.dev conserva un bisel y una sombra al pasar el cursor. Mantengo esas diferencias en cada producto, aunque quede algo de duplicación. Un patrón compuesto solo se comparte cuando tres productos independientes necesitan el mismo comportamiento y las mismas responsabilidades.
En qué estado está#
El registro del 2 de septiembre de 2026 indica que ambos productos adoptaron v0.13.2. Existe una etiqueta v0.13.3 y la rama principal revisada contiene desarrollo posterior. Los productos eligen sus actualizaciones de forma deliberada. Esos registros describen la adopción del código; no establecen qué versión sirve actualmente cada página publicada.
Mi papel#
Dirijo las decisiones visuales, la arquitectura, los límites entre responsabilidades y la aceptación de cambios. La IA apoya la implementación. Reviso sus resultados frente al código y las pruebas, y sigo siendo responsable de las decisiones que acepto.
Para profundizar#
Cada sección siguiente amplía un aspecto del proyecto con las razones de las decisiones, ejemplos concretos y los contratos técnicos:
Origen · Valores de diseño · Comportamiento de componentes · Límites entre productos · Versiones y adopción · Papel y estado del proyecto
La base nació dentro de yesid.dev. El primer paso fue extraer las partes reutilizables sin cambiar de paso la apariencia del sitio. Si un color, un espacio o una animación cambiaba durante ese traslado, resultaba más difícil saber si la diferencia era una decisión de diseño o un error de extracción.
Esa distinción definió la primera versión. v0.1.0 conserva un punto de referencia concreto del sitio original, con las diferencias de la extracción documentadas. Entre las excepciones registradas están los cambios en las rutas de importación y la decisión de mantener ciertos movimientos más especializados dentro de la aplicación. Los cambios posteriores reciben nuevas versiones. La referencia inicial sigue disponible y su etiqueta de versión no se mueve.
Así, el proyecto podía responder dos preguntas distintas: ¿la extracción conservó la base prevista?, y ¿vale la pena adoptar un cambio de diseño posterior? Mover código y modificar la experiencia pueden ser decisiones útiles, pero cada una necesita su propia revisión.
A qué productos les sirve#
Transit y yesid.dev necesitan una relación visual reconocible mientras cumplen funciones diferentes. Su base compartida incluye colores, tipografía, controles de interfaz y mecanismos de interacción. Cada producto sigue definiendo la estructura de sus páginas, navegación, contenido, datos y entorno de ejecución. La base no decide cómo se procesan los datos de Transit ni qué contenido editorial publica yesid.dev.
El repositorio también contiene una galería privada de componentes. Usa los paquetes directamente y hace visible su comportamiento con ejemplos neutros. Es un lugar útil para examinar un control antes de incorporarlo a un producto. Se trata de un entorno interno de integración, con una función diferente a la de los dos productos externos y su propio límite de versiones.
Esa distinción explica el propósito del proyecto. Un botón compartido puede tener una apariencia común y un comportamiento predecible. No puede decidir qué significa una acción en una herramienta de transporte ni qué mensaje corresponde a una página de proyecto. Quería darles un lugar claro a las decisiones reutilizables y mantener las decisiones del producto donde se pudieran entender en contexto.
La implementación usa un espacio de trabajo con Bun y Turborepo. Los paquetes relacionados se mantienen juntos y la galería está en el directorio de aplicaciones. Esa organización permite trabajar sobre los valores de diseño, los componentes y sus ejemplos en un mismo repositorio. La distribución sigue pasando por versiones deliberadas: que un cambio funcione en la galería no lo convierte automáticamente en una actualización de los productos.
El lenguaje visual de la marca toma referencias de la infraestructura y la señalización. El naranja identifica la interacción. El amarillo sirve como marcador y orientación. El blanco reflectante y el negro estructural definen el contraste y el carácter de la paleta. Otros colores comunican estados como éxito o error. La intención es tener un vocabulario reconocible que sirva para distintos tipos de información.
Estas decisiones se guardan en valores de diseño estructurados, conocidos como tokens. Un token le da un nombre y un significado acordado a un color, un tamaño de texto, un espacio, un radio o una duración de animación. Los componentes usan esos valores en lugar de escoger, cada uno por su cuenta, una variante casi idéntica. Así resulta más fácil revisar la relación entre una decisión de diseño y sus usos.
Una fuente que produce varios resultados#
La fuente editable es un archivo JSON en formato DTCG, una forma estructurada de describir valores de diseño. Los generadores convierten esa fuente a los formatos que necesitan las hojas de estilos, el código de movimiento y la referencia de diseño. Los archivos generados se comparan con esa fuente para detectar copias editadas a mano que podrían convertirse en una versión competidora del diseño.
El adaptador de generación del repositorio deja explícitas las cuatro rutas de salida:
export const artifactPaths = [
'DESIGN.md',
'apps/gallery/src/app.css',
'packages/motion/src/tokens.ts',
'packages/tokens/tokens.css',
] as const;Los archivos cumplen funciones diferentes: referencia de diseño, estilos de la galería, valores de movimiento y hoja de estilos compartida. El motor de generación recibe datos y devuelve contenido. Un adaptador del repositorio decide dónde escribirlo. Cada producto que usa el motor conserva sus propias rutas de salida y debe identificar correctamente su fuente en los encabezados de los archivos generados.
Esa separación evita que el paquete compartido tenga que conocer la estructura de carpetas de una aplicación. También permite que un producto mantenga valores locales revisados o una organización de archivos particular sin presentarlos como decisiones universales de la marca.
Un cambio pequeño que deja un recorrido visible#
Una prueba del repositorio ofrece un ejemplo concreto. En una copia temporal preparada para la prueba, cambia la duración rápida de animación de 150 a 151 milisegundos. Espera que cambien el TypeScript de movimiento y el CSS del paquete, y que la hoja de estilos de la galería permanezca intacta. Después ejecuta el generador en modo de verificación y espera que no haya más cambios. Ese milisegundo adicional es un dato de prueba, no un rediseño ni una mejora medida.
El ejemplo comprueba dos propiedades útiles. Un cambio en la fuente debe llegar a las salidas que lo usan, y repetir la generación debe producir el mismo resultado. La herramienta compara el contenido existente antes de guardarlo, de modo que no necesita volver a escribir los archivos que no cambiaron.
Otras verificaciones acompañan ese recorrido: los archivos guardados en el repositorio se comparan con el contenido generado, el comando de integración continua de tokens detecta diferencias y un control local opcional de commit rechaza archivos generados preparados sin un cambio pertinente en la fuente. Los finales de línea se mantienen iguales entre sistemas operativos porque una comparación byte a byte también detecta esas diferencias invisibles. Cada mecanismo ayuda a detectar desviaciones dentro de un alcance definido.
Valores fluidos y conexión con las herramientas de diseño#
Algunos tamaños de texto y espacios son fluidos. Cambian con el ancho disponible entre un mínimo y un máximo. La fuente conserva las tres partes del cálculo, incluido el valor preferido, y el generador CSS produce una expresión clamp. Se conserva así la decisión original, en vez de guardar solo el tamaño que aparece en una captura.
Los formatos de destino tienen capacidades distintas. La exportación a Figma lleva la expresión clamp como texto; no la convierte en una fórmula responsive nativa. La tipografía de la referencia de diseño usa el máximo estructurado cuando su formato solo acepta una dimensión. El recorrido de ida y vuelta con Figma también sigue siendo manual: exportar las variables, aplicarlas con las herramientas de diseño y verificar la exportación de regreso. Hay una conexión entre código y diseño, con límites de traducción explícitos.
La galería usa el código real de los componentes con contenido de demostración. Incluye botones, pestañas, un selector con búsqueda, contenido plegable, áreas de desplazamiento y otros controles. También muestra elementos propios de la identidad: marcadores de estación, etiquetas de sección, marcos inspirados en planos técnicos y un cursor de terminal.
El estado inicial de un control solo responde parte de las preguntas. La galería incluye controles deshabilitados, carga, errores, contenido que desborda su espacio y etiquetas proporcionadas por el producto. Los temas claro y oscuro permiten examinar las mismas piezas en condiciones visuales diferentes. Los escenarios en el navegador cubren las interacciones renderizadas, la adaptación del contenido al espacio disponible y comportamientos de accesibilidad, además de comparar capturas.
La responsabilidad de un componente#
Aquí, un contrato describe qué debe mostrar un componente, cómo debe responder y qué decisiones conserva el producto que lo usa. También abarca detalles que no siempre aparecen en la primera captura.
El selector con búsqueda es un ejemplo útil. Sus mecanismos compartidos manejan la apertura, el valor seleccionado, la consulta escrita y el borrado. El producto proporciona las opciones, sus valores estables, las etiquetas visibles, el texto de búsqueda y los textos de accesibilidad. El contrato revisado también indica que cerrar el selector reinicia la consulta temporal y que un cambio externo del valor actualiza la etiqueta mostrada. Son comportamientos observables que el producto puede usar y probar.
Algunos requisitos atraviesan el límite del paquete. El selector usa una variable de tamaño mínimo de objetivo táctil que el producto debe definir en 44 píxeles. El producto también debe proporcionar una etiqueta de cierre traducida cuando usa un panel de tipo Sheet. Reutilizar un control incluye obligaciones de configuración; importarlo no basta para establecer que la página completa es usable.
El mismo principio se aplica a la semántica HTML. Un control que funciona como enlace y otro que funciona como botón exponen los atributos y la referencia del elemento que realmente renderizan. Esto mantiene la interfaz de programación alineada con la interfaz real, en vez de aceptar combinaciones que el componente no puede cumplir.
Movimiento y movimiento reducido#
El movimiento también tiene reglas. Los efectos más grandes o continuos tienen en cuenta la preferencia de movimiento reducido, mientras algunas respuestas breves a una interacción permanecen. La política distingue el seguimiento del puntero, los cambios grandes de escala, el movimiento continuo y los efectos de desplazamiento de respuestas menores, como un cambio de color o una reacción breve al presionar.
Por ejemplo, al activar el efecto, el desplazamiento de una tarjeta que sigue el puntero se desactiva si se solicita movimiento reducido o si el dispositivo no permite pasar el puntero por encima. Estas tres verificaciones vienen del comportamiento de movimiento de la tarjeta:
if (typeof window === 'undefined') return { destroy: () => {} };
if (isPrefersReducedMotion()) return { destroy: () => {} };
if (!window.matchMedia('(hover: hover)').matches) return { destroy: () => {} };La primera verificación también permite que la acción no haga nada en un entorno sin navegador. Si las condiciones permiten el efecto, el código conecta los eventos del puntero y actualiza los desplazamientos que usan los elementos dentro de la tarjeta. Salir de la tarjeta devuelve esos valores a cero, y destruir la acción retira los manejadores de eventos.
El momento de las verificaciones forma parte del comportamiento. Esta lectura síncrona de la preferencia ocurre durante la inicialización. Para esta política, un cambio en la configuración del sistema operativo se aplica en la siguiente inicialización o navegación; no significa que cada acción ya conectada responda de inmediato. Otros comportamientos tienen sus propias reglas CSS, como detener el pulso de un indicador de carga tipo Skeleton o quitar la transición de un contenido plegable.
El contenido cerrado también necesita algo más que una animación. El contenido plegable compartido puede seguir montado mientras queda inerte y oculto para las tecnologías de asistencia cuando está cerrado. Un producto que reemplace una envoltura más sencilla debe tener en cuenta la estructura adicional y el comportamiento del estado cerrado. La transición visual y la posibilidad de interactuar con el contenido son asuntos distintos que deben revisarse.
Qué permiten establecer las verificaciones#
Las pruebas de los paquetes examinan los contratos compartidos. La galería examina su integración en una interfaz renderizada. Los motores de calidad revisan aspectos como contraste, patrones de estilo y cobertura de metadatos para buscadores, según las reglas que proporciona el producto. Este elige su paleta, umbrales, exclusiones y resultados esperados; el motor devuelve los hallazgos.
Así, una verificación fallida apunta a una responsabilidad concreta. Una interacción compartida incorrecta corresponde al paquete. Un requisito visual propio del producto corresponde a su adaptación local. Una captura de la galería ofrece evidencia sobre la galería. La accesibilidad de la página completa y el comportamiento del producto todavía requieren una revisión en su contexto real.
Las decisiones más importantes tienen que ver con lo que conserva cada producto. Reutilizar crea una relación de mantenimiento: cuando varios productos dependen del mismo comportamiento, cambiarlo les exige considerar las consecuencias.
El conflicto entre las tarjetas#
Transit y yesid.dev comparten una base, pero sus tarjetas no tienen que ser iguales. El contrato documentado de Transit exige una tarjeta plana, sin sombra ni borde resaltado. yesid.dev conserva un bisel y una sombra al pasar el cursor. Son requisitos explícitos, incompatibles y respaldados por pruebas de cada producto.
La superficie común puede seguir compartida mientras una adaptación o un estilo local maneja la diferencia. El paquete compartido no consulta el nombre de la aplicación para decidir qué apariencia renderizar. Si una abstracción propuesta necesita conocerlo, las reglas del proyecto devuelven ese comportamiento al producto.
La consecuencia va más allá de una preferencia de estilo en el código. Si se añadiera el bisel a la tarjeta compartida para resolver la necesidad de un sitio, Transit recibiría un cambio que sus propias pruebas rechazan. Si el paquete acumulara excepciones con el nombre de cada aplicación, mantenerlo exigiría conocer cada vez más reglas particulares de los productos.
Qué cubre realmente la regla de tres#
Los patrones compuestos siguen una regla de tres: tres consumidores independientes, es decir, productos que usan el componente, deben necesitar el mismo contrato antes de promover el patrón a un paquete compartido mediante una versión deliberada. Es una regla de gobierno del proyecto. No cuenta clientes, no fija una meta de despliegues ni afirma que cada control básico ya tenga tres usos en producción.
CollapsibleSection ilustra la diferencia. Dos productos pueden mostrar un título, un chevrón y contenido oculto, y aun así diferir en la composición del encabezado, la persistencia, las señales de control y el comportamiento de las animaciones. Las piezas plegables básicas pueden compartirse. El controlador de la sección completa sigue siendo local hasta que los usos establezcan un contrato común.
La composición del pie de página sigue el mismo razonamiento. Pequeñas piezas compartidas pueden ayudar a construirlo, mientras su navegación, información de estado, atribución y distribución siguen siendo decisiones del producto. Una apariencia familiar no determina por sí sola quién debe hacerse cargo de toda la composición.
Esto deja parte de la duplicación en su lugar. El costo es mantener esas piezas locales. A cambio, las diferencias siguen siendo explícitas mientras los requisitos continúan siendo distintos. Compartir se vuelve una decisión respaldada por el uso, en lugar de una suposición basada en dos archivos parecidos.
Estado, configuración y control del producto#
Una vista controlada puede mostrar un estado y ofrecer funciones de respuesta sin decidir dónde se guarda ese estado ni qué significa la acción. QuietModeButton, por ejemplo, comparte la estructura de dos botones, los íconos y las dimensiones de interacción. El producto proporciona los textos, el estado actual, la persistencia y las dos acciones. Reutilizar la apariencia no traslada el control del producto al paquete.
La configuración también tiene un límite. El vocabulario que se usa para combinar clases de interfaz queda fijo al iniciar la aplicación, por cada conjunto de módulos cargado. Una inicialización equivalente puede repetirse; una configuración contradictoria genera un error. No debe depender de una solicitud, un usuario, una organización usuaria ni del idioma actual. Los módulos del navegador y los del renderizado en servidor tienen su propia inicialización. Así, una configuración compartida no se convierte en un lugar para guardar estado cambiante de una persona.
Dominios más allá de la interfaz visible#
La base ya incluye mecanismos que van más allá de los estilos. El paquete de SEO construye metadatos estructurados y entradas de mapas del sitio, mientras el producto conserva el contenido, las rutas canónicas, las decisiones de indexación y las plantillas de imágenes. El enrutamiento por idioma comparte mecanismos para interpretar y localizar rutas; cada producto elige sus idiomas, páginas publicadas, reglas de respaldo e integración con el framework.
La analítica tiene un límite parecido. El paquete compartido proporciona mecanismos de estado y envío que tienen en cuenta el consentimiento. El producto proporciona su dominio, catálogo de eventos, textos de consentimiento, decisiones de almacenamiento y transporte. En el código revisado, el consentimiento y el dominio se verifican antes de cargar el transporte y de nuevo antes de enviar. Usar estos mecanismos no define por sí solo la política de privacidad del producto.
Estos dominios tienen una razón común para estar aquí: sus mecanismos repetibles pueden servir a varios productos. Cada uno conserva una responsabilidad acotada. La navegación, los contratos de datos, las credenciales, los adaptadores de despliegue y las decisiones propias del producto permanecen fuera de la base.
Cada producto adopta una versión exacta. Publicar una nueva versión de la base no cambia automáticamente todos los sitios. El cambio ocurre mediante una adopción revisada en el producto que la recibe, con sus propios archivos generados y verificaciones de aceptación.
Versiones coordinadas y una línea distinta para las herramientas#
Siete paquetes avanzan juntos: tokens, movimiento, verificaciones de calidad, interfaz, mecanismos de SEO, analítica y enrutamiento por idioma. Coordinarlos le da a cada versión un conjunto conocido de paquetes. También significa que un cambio limitado a una parte debe revisarse dentro de esa versión común. La galería privada queda fuera de ese grupo, y la configuración compartida de compilación y tareas tiene una línea de versiones independiente.
Los paquetes distribuyen código fuente TypeScript y Svelte. Los productos importan las familias de componentes que necesitan y activan explícitamente las hojas de estilos compartidas. Las obligaciones de integración quedan visibles: un producto que usa Tailwind debe analizar el código fuente instalado de la interfaz, y su hoja de estilos debe definir los valores de aplicación que necesitan los componentes.
Los reportes de interfaz pública permiten revisar los cambios de la API. Las notas que acompañan cada cambio describen su efecto visible para el producto y cualquier migración. La política de compatibilidad también distingue entre añadir una capacidad, corregir un defecto y retirar un contrato establecido. Retirar un contrato estable exige tanto un periodo documentado de al menos 90 días como una versión menor intermedia. Son reglas que se mantienen, no una razón para omitir la revisión de una actualización.
Saber qué se instaló#
La herramienta de adopción instala el archivo de una versión exacta y guarda un registro de lo que recibió en un manifiesto. El registro identifica la etiqueta, el commit asociado, el tamaño y la huella digital del archivo, los paquetes incluidos, la identidad de la herramienta de adopción y la huella del contenido instalado. Vincula los archivos con una versión específica y les da a las verificaciones posteriores una referencia concreta.
El modo de verificación sin conexión compara los archivos instalados con su registro. No contacta el servicio de publicación para demostrar que pasaron las verificaciones de origen ni establece que el producto funcione correctamente. La procedencia de la versión, la integridad local y la aceptación del producto responden preguntas diferentes.
La regla de flujo en una sola dirección se desprende de esa estructura. Los productos no corrigen el código compartido modificando su copia instalada. Un defecto común se corrige en la base y se entrega en una nueva versión. Una diferencia propia del producto corresponde a su adaptación local. De lo contrario, la versión indicada en el manifiesto dejaría de explicar el código que realmente ejecuta el producto.
Seguir un cambio hasta el producto#
Pensemos en un cambio revisado de una duración de animación compartida. La fuente cambia en la base, se examinan los archivos generados y se ejecutan las verificaciones correspondientes del paquete y de la galería. La versión describe el cambio. Después, Transit o yesid.dev puede elegir esa versión exacta, regenerar sus propias salidas y revisar dónde aparece esa duración en su interfaz.
Cambiar un componente plantea más preguntas. ¿La nueva estructura HTML afectó un selector del producto? ¿La tarjeta local conserva la superficie prevista? ¿El contenido cerrado sigue comportándose correctamente? ¿Caben las etiquetas traducidas? El contrato de adopción exige las pruebas pertinentes del producto, verificación de tipos, compilación y comparación en el navegador según los temas, tamaños y estados de interacción afectados.
Este proceso añade trabajo a una entrega. También permite seguir la decisión: qué cambió en la base, qué producto lo aceptó y qué se verificó allí. Una ejecución exitosa en la galería no reemplaza esas respuestas, porque usa los paquetes del espacio de trabajo y su propia composición de demostración.
Volver atrás sigue el mismo recorrido deliberado. El producto adopta una versión exacta aceptada anteriormente, ajusta sus dependencias al conjunto de paquetes de esa versión, regenera sus archivos y repite las verificaciones. Las versiones anteriores pueden contener menos paquetes. Restaurar archivos sin revisar esa relación de dependencias dejaría una parte de la decisión de actualización sin resolver.
Mi papel abarca la dirección de marca, la arquitectura, los límites entre responsabilidades y las decisiones de aceptación. La implementación tiene apoyo de IA. El modelo de trabajo documentado exige revisar los resultados de los agentes, cuestionar supuestos y contrastar las afirmaciones con el código y las pruebas. Sigo siendo responsable de lo que decido aceptar.
El registro documenta la adopción de v0.13.2 por Transit y yesid.dev al 2 de septiembre de 2026. La base también tiene una etiqueta de versión v0.13.3. En la rama principal hay mejoras de robustez posteriores, separadas de esa versión etiquetada. La explicación técnica de esta historia describe el código revisado y sus contratos documentados. Un registro de adopción identifica el código que recibió un producto; sus páginas desplegadas todavía necesitan una verificación propia.
El proyecto convirtió la responsabilidad en una parte concreta del diseño. Un color tiene una fuente. Un componente tiene una función. Una diferencia entre productos tiene un lugar explícito. Una versión tiene una identidad, y aceptarla exige trabajo en el producto que la recibe.
Para alguien que esté considerando trabajar conmigo, esa es la parte útil de este caso de estudio: cómo abordo una interfaz que debe seguir evolucionando después del primer lanzamiento. Los detalles visuales importan, al igual que dejar comprensible el próximo cambio. Sigo desarrollando esa práctica mediante las decisiones, verificaciones y concesiones que esta base hace visibles.
Una base compartida para valores de diseño, componentes y movimiento. Cómo Transit y yesid.dev la adoptan sin perder sus responsabilidades de producto.
Construyamos algoque se mueva.
Base de datos, pipeline, tablero, sitio web: donde se atasca la cosa, ahí empezamos.