← RETURN_TO_DB
CLASSIFICATION_LEVELPUBLIC
REF_ID: 8B976
DATE06.2026

Guía Base UI UX, Personalidad y Arquitectura Compartida (Angular + Flutter)

Case study data record.

Tech_Stack / Tags

FLUTTERANGULARPATRONESDESIGN SYSTEMCAPAS

Meta

  • Creado: Jun 24, 2026, 7:37:21 AM
  • Actualizado: Jun 24, 2026, 7:56:14 AM

Una metodología en 5 pasos para construir productos que se vean profesionales, tengan carácter propio y compartan la misma arquitectura sin importar el framework.


Cómo leer esta guía

El orden importa. Cada paso depende del anterior, y saltártelos es la razón #1 por la que una app "se ve hecha por defecto". La regla mental es:

Primero decides qué (Paso 1) → luego el ADN visual (Paso 2) → cómo se siente (Paso 3) → cómo se comporta (Paso 4) → y recién al final cómo lo organizas en código (Paso 5).

No abras el editor de código hasta el Paso 5. En serio.

Voy a usar un ejemplo que arrastraré por toda la guía para que sea concreto: una app para iPad que gestiona facturas de forma rápida.


Paso 1 — La idea y el alcance (sin diseño ni código)

1.1 El propósito en una frase

Escribe una sola frase que diga qué hace tu producto y para quién. Si necesitas un "y" para unir dos ideas, tu producto todavía no está enfocado.

"Una app para iPad que permite a freelancers crear y enviar facturas en menos de 30 segundos."

Fíjate que esa frase ya esconde tres cosas valiosas: el usuario (freelancers), el trabajo principal (crear/enviar factura) y una promesa (en 30 segundos). Esa promesa es la que vas a defender en cada decisión de diseño.

1.2 Lista de funcionalidades (Features)

Divide la idea en bloques que el usuario necesita para cumplir su trabajo. Cada bloque será una carpeta en tu código. Para cada feature anota su trabajo (qué resuelve), no su pantalla.

Feature Trabajo del usuario ¿Imprescindible para v1?
auth Entrar de forma segura a sus datos
dashboard Ver de un vistazo cuánto le deben
invoicing Crear, ver y enviar facturas
clients Guardar a quién le factura Quizás (puede ir en v2)
settings Configurar su negocio (logo, impuestos) No (v2)

El truco de principiante que cambia todo: marca qué es v1 y qué no. Una app pequeña pero terminada siempre se ve más profesional que una app grande llena de pantallas a medias.


Paso 2 — El sistema de diseño (tus tokens, tu ADN visual)

Los tokens son las variables de tu diseño. Definirlos primero garantiza que, aunque la app sea sencilla, se vea coherente — y coherencia es el 80% de lo que el ojo lee como "profesional".

2.1 La idea clave que casi nadie te explica: tokens en dos capas

No definas un solo nivel de tokens. Define dos:

Primitivos — la paleta cruda, sin significado. Solo nombres descriptivos:

slate-50:  #F8F9FA
slate-800: #1E293B
white:     #FFFFFF
indigo-600:#4F46E5

Semánticos — el rol que cumple cada color, apuntando a un primitivo:

color-background      → slate-50
color-surface         → white
color-primary         → indigo-600
color-text            → slate-800
color-text-muted      → slate-500
color-border          → slate-200

¿Por qué molestarte? Porque el día que quieras cambiar de "indigo" a "negro brutalista", tocas una línea (color-primary → black) y toda la app cambia. Tus botones nunca dicen #4F46E5; dicen color-primary. Esta separación es lo que hace que un sistema escale.

2.2 Los seis grupos de tokens (no solo color)

La mayoría de principiantes define color y tipografía y se detiene. Un sistema profesional define seis grupos. Define todos antes de diseñar:

1. Color (semántico, máximo 4–6 roles) Background, Surface, Primary, Text, Text-muted, Border. Una regla de oro: el texto nunca es negro puro (#000) sobre blanco puro — usa un gris muy oscuro (#1E293B). El negro puro "vibra" y cansa la vista.

2. Tipografía (máximo 2 familias)

  • Display: con personalidad, para títulos. Úsala con restricción (solo títulos grandes).
  • Body: limpísima y legible, para texto largo y botones (Inter, Roboto, Geist).
  • Define también una escala de tamaños fija, no inventes tamaños: xs 12 · sm 14 · base 16 · lg 20 · xl 28 · 2xl 40.

3. Espaciado (escala de 4 en 4) 4 · 8 · 12 · 16 · 24 · 32 · 48 · 64. Nunca pongas un margen de "23px sobre la marcha". Esta es la regla más fácil de seguir y la que más rápido hace que todo se vea ordenado.

4. Radios (la decisión de tu vibe)

  • 0px → crudo, brutalista, técnico.
  • 8px → minimalista amigable (lo más seguro para empezar).
  • 16px+ → suave, juguetón, consumer. Elige uno como base y sé consistente. Mezclar radios al azar es la marca del amateur.

5. Elevación / sombras Define 2–3 niveles (none · sm · md) en vez de inventar sombras. En estilos brutalistas, en lugar de sombras difusas usa sombras duras y desplazadas (4px 4px 0 #000), que es parte de su firma visual.

6. Movimiento (¡sí, las animaciones también son tokens!) Esto es lo que casi nadie hace y lo que separa una app "viva" de una rígida:

duration-fast:  150ms   (hovers, cambios pequeños)
duration-base:  250ms   (transiciones de UI, aparecer/desaparecer)
duration-slow:  400ms   (cambios de pantalla, modales)

easing-standard: cubic-bezier(0.4, 0, 0.2, 1)   (entradas y salidas normales)
easing-spring:   curva con rebote                (para deleite, botones, éxito)

Definir esto antes evita que cada animación dure un tiempo distinto y se sienta caótica.

2.3 La REGLA DE ORO cross-platform

Define los tokens UNA sola vez, en un formato neutral (JSON), y genera desde ahí el tema de cada plataforma. Una única fuente de verdad.

📄 tokens.json   ←  la ÚNICA fuente de verdad (color, type, spacing, motion…)
       │
       ├──►  theme.dart   (para Flutter)
       └──►  theme.ts      (para Angular)

La herramienta estándar para esto se llama Style Dictionary (de Amazon): lee tu tokens.json y escupe automáticamente las variables para Dart, para CSS/SCSS, para TypeScript, etc. Así, cuando cambias un color, ambas apps cambian a la vez y nunca se desincronizan.

Cuando empiezas, puedes hacerlo a mano (un theme.dart y un theme.ts que copien los mismos valores), pero piensa siempre en tokens.json como el "original" y los demás como "copias generadas". Esa mentalidad es la que hace el diseño verdaderamente compartido.


Paso 3 — Personalidad y micro-animaciones (lo que hace que se sienta vivo)

Aquí está tu objetivo #2. Una UI sin movimiento se siente como una foto; con el movimiento correcto, se siente como un objeto físico que responde. Pero animar por animar arruina una app (y delata que fue generada sin criterio). Cada animación debe tener un trabajo.

3.1 Las cuatro razones legítimas para animar

  1. Feedback — confirmar que el sistema te oyó. Un botón que se hunde 2px al presionarlo.
  2. Continuidad — explicar de dónde viene y a dónde va algo. Un modal que crece desde el botón que lo abrió, en vez de aparecer de golpe.
  3. Jerarquía / atención — guiar el ojo. El total de la factura que cuenta hacia arriba ($0 → $1,250) cuando se calcula.
  4. Deleite — el toque de personalidad. Un check que se dibuja con un pequeño rebote al marcar "factura pagada".

Si una animación no cae en ninguna de estas cuatro, bórrala.

3.2 La regla del "gasta tu osadía en un solo lugar"

No hagas que todo tenga personalidad — eso es ruido. Elige un elemento firma: el momento que tu usuario recordará. En la app de facturas podría ser la animación de "factura enviada" (el papel que se dobla y sale volando). Todo lo demás: discreto, rápido, casi invisible.

3.3 Catálogo de micro-interacciones para empezar

Elemento Qué pasa al interactuar Token de tiempo
Botón Baja de escala a 0.97 + se aclara al presionar fast
Card / tarjeta Sube 2–4px y gana sombra md al hacer hover fast
Aparición lista Cada item entra con fade + slide-up, escalonado (50ms) base
Cambio de pantalla Desliza/funde con easing-standard slow
Éxito (enviado) Check animado con easing-spring (rebote) base
Error Shake horizontal corto del campo fast
Carga Skeleton que pulsa (no un spinner genérico, ver Paso 4) loop

3.4 Cómo se traduce a cada framework (misma idea, distinta herramienta)

Concepto Flutter Angular
Animación implícita AnimatedContainer, AnimatedOpacity Transiciones CSS sobre cambio de clase
Animación con control AnimationController + Tween Angular Animations (trigger, state)
Rebote / spring CurvedAnimation con Curves.elasticOut cubic-bezier con overshoot / @angular/animations
Entrada escalonada flutter_animate (paquete) @stagger() en Angular Animations
Respetar reduce-motion MediaQuery.disableAnimations prefers-reduced-motion media query

Piso de calidad obligatorio: siempre respeta prefers-reduced-motion. Hay personas a las que el movimiento les causa mareo. Si el usuario lo desactivó en su sistema, tus animaciones deben reducirse a un simple fundido o desaparecer.


Paso 4 — UX: cómo se comporta (no solo cómo se ve)

Tu borrador era fuerte en UI; esta capa es la UX que le faltaba. Es lo que hace que la app se sienta terminada en vez de rota.

4.1 Los cuatro estados de TODA pantalla

El error de principiante #1: diseñar solo el estado "lleno de datos bonitos". Toda pantalla que muestre datos tiene en realidad cuatro estados, y debes diseñar los cuatro:

  1. Vacío — el usuario aún no tiene datos. No es una pantalla en blanco: es una invitación a actuar. ("Aún no tienes facturas. Crea la primera →").
  2. Cargando — usa skeletons (siluetas grises del contenido que viene), no un spinner centrado. El skeleton hace que la espera se sienta más corta y predice el layout.
  3. Error — explica qué pasó y cómo arreglarlo, en la voz de la app, sin disculpas vagas. ("No pudimos cargar tus facturas. Revisa tu conexión y reintenta.")
  4. Con datos — el estado feliz.

Diseña siempre vacío → cargando → error → datos. Esta sola disciplina te pone por encima del 90% de las apps de principiante.

4.2 El texto es parte del diseño

Las palabras de tu interfaz son material de diseño, no decoración. Tres reglas que rinden mucho:

  • Nombra las cosas por lo que el usuario controla, no por cómo está hecho el sistema. El usuario "envía una factura", no "ejecuta un POST".
  • El botón dice exactamente qué pasa. "Enviar factura", no "Aceptar". Y el nombre se mantiene por todo el flujo: si el botón dice "Enviar", el mensaje de éxito dice "Factura enviada".
  • Voz activa, frases cortas, sin relleno. "Guardar cambios" pesa más que "Proceder a guardar".

4.3 El piso de accesibilidad (no negociable)

No es opcional ni "para después". Es barato si lo haces desde el inicio:

  • Contraste: el texto debe tener contraste suficiente sobre su fondo (mínimo 4.5:1 para texto normal). Hay extensiones que lo miden en segundos.
  • Áreas táctiles: mínimo 44×44px en lo que se toca (especialmente en iPad).
  • Foco visible: quien navega con teclado debe ver dónde está parado.
  • No solo color: no comuniques "error" únicamente con rojo; añade un ícono o texto (hay personas daltónicas).

Paso 5 — Arquitectura compartida: Feature-Driven (recién aquí tocas código)

La gran idea: en lugar de agrupar por tipo de archivo (todos los botones juntos, todas las pantallas juntas), agrupas por funcionalidad (feature). Cuando trabajas en "facturación", todo lo de facturación está en una sola carpeta.

Lo que se comparte entre Angular y Flutter NO es el código — es la estructura y la filosofía de capas. El mismo plano, materiales distintos.

5.1 La estructura de carpetas (idéntica en ambos frameworks)

📁 tu_proyecto/
├── 📁 core/                  ← lo global: lo que usa TODA la app
│   ├── 📄 theme              # tus tokens (theme.dart / theme.ts)
│   ├── 📄 api_service        # conexión a la base de datos / backend
│   └── 📁 utils/             # helpers, constantes, formateadores
│
├── 📁 shared/                ← componentes REUTILIZABLES sin lógica de negocio
│   └── 📁 ui/                # AppButton, AppTextField, AppCard… (usan los tokens)
│
└── 📁 features/              ← ¡la magia del Feature-Driven!
    ├── 📁 auth/
    │   ├── 📁 presentation/  # pantallas + widgets SOLO de auth
    │   ├── 📁 domain/        # las reglas: "qué es un usuario válido"
    │   └── 📁 data/          # de dónde vienen los datos (API, repos)
    │
    ├── 📁 dashboard/
    │   ├── 📁 presentation/  # pantalla + tarjetas resumen, gráficos
    │   ├── 📁 domain/
    │   └── 📁 data/
    │
    └── 📁 invoicing/
        ├── 📁 presentation/
        ├── 📁 domain/
        └── 📁 data/

5.2 Por qué tres capas dentro de cada feature

Esto es lo que sube tu objetivo #3 (la "mejor arquitectura"). Cada feature se parte en tres capas con una regla de dependencia: presentation → domain → data, nunca al revés.

  • presentation — lo que el usuario ve y toca (pantallas, widgets/componentes, estado de UI). No sabe de dónde salen los datos; solo los pide.
  • domain — el corazón limpio: las reglas de negocio y los modelos. "Una factura tiene fecha, cliente y total"; "una factura no puede enviarse sin cliente". Esta capa no depende de Flutter ni de Angular ni del internet — es Dart/TypeScript puro. Por eso es la más fácil de portar y la más fácil de testear.
  • data — el plomero: habla con la API o la base de datos y entrega modelos limpios al domain. Si mañana cambias de backend, solo tocas esta capa.

La ventaja: puedes cambiar el diseño (presentation) sin tocar las reglas (domain), o cambiar el backend (data) sin tocar la pantalla. Cada parte cambia por su cuenta.

5.3 Mapa de conceptos Flutter ↔ Angular

Misma arquitectura, distinto vocabulario. Esta tabla es tu traductor:

Concepto Flutter Angular
Bloque de UI Widget Component
Pantalla Screen / Page (un Widget) Routed Component
Estilos globales ThemeData CSS variables / theme service
Estado / lógica de UI Riverpod, BLoC, Provider Services + Signals / RxJS
Inyección de dependencias get_it, Riverpod Inyector nativo de Angular
Llamadas HTTP dio / http HttpClient
Modelo de datos class Invoice {...} interface Invoice {...}
Navegación go_router Angular Router

Decide tu manejador de estado y mantenlo. En Flutter, Riverpod es una opción moderna y recomendable para empezar. En Angular, Signals (lo más nuevo) o Services + RxJS.

5.4 La regla que mantiene todo limpio

Un componente en shared/ui (como AppButton) solo puede usar tokens del core/theme. Nunca un color "a mano". Un widget dentro de features/invoicing solo vive ahí; si lo necesitas en dos features, entonces lo subes a shared/. No antes.

Esto evita el caos donde "todo usa todo" y nadie sabe qué rompe qué.


El orden de ataque (tu checklist)

Cuando arranques un proyecto nuevo, sigue exactamente este orden:

  1. [ ] Escribe el propósito en una frase.
  2. [ ] Lista las features y marca cuáles son v1.
  3. [ ] Crea tokens.json con los 6 grupos (color, type, spacing, radius, elevation, motion).
  4. [ ] Elige tu elemento firma (la animación/momento que te van a recordar).
  5. [ ] Para cada pantalla, diseña los 4 estados (vacío, cargando, error, datos).
  6. [ ] Escribe el texto de botones y errores en voz activa.
  7. [ ] Crea la estructura de carpetas core / shared / features.
  8. [ ] Construye primero los componentes shared/ui (botón, input, card) usando solo tokens.
  9. [ ] Construye feature por feature, empezando por la más imprescindible (auth o la principal).
  10. [ ] Revisa accesibilidad y reduce-motion antes de dar por terminada cada pantalla.

Errores comunes de principiante (y su antídoto)

  • Inventar márgenes y tamaños sobre la marcha. → Usa siempre la escala de espaciado y tipografía.
  • Diseñar solo el estado "con datos". → Diseña los 4 estados, siempre.
  • Negro puro sobre blanco puro. → Gris muy oscuro sobre blanco hueso.
  • Mezclar radios y sombras al azar. → Un radio base, 2–3 niveles de sombra, y basta.
  • Animar todo. → Una firma con personalidad; el resto, discreto y rápido.
  • Agrupar por tipo de archivo. → Agrupa por feature.
  • Copiar colores #hex en cada botón. → Apunta siempre al token semántico.
  • Dejar accesibilidad "para el final". → Es barata al inicio, carísima al final.

Una última idea

La elegancia no es agregar; es ejecutar bien una visión simple. Una app con 4 pantallas, 6 colores, 2 fuentes y una sola animación memorable — toda coherente — se ve más profesional que una con 20 pantallas y todo distinto. Empieza pequeño, termínalo bien, y crece desde ahí.

Escrito por@ARBE

Comentarios (0)