# VMS-Sailor — Design System > Sistema visual completo del producto. Aplica a Studio (PySide6), Runtime > cliente desktop (PySide6) y Mobile (Flutter). Los mockups HTML en > `docs/mockups/` son la **referencia visual canónica** para los sprints > de UI (Sprint 1, 6, 11). --- ## 1. Filosofía visual **"Deep ocean meets technical precision."** VMS-Sailor opera 24/7 en cabinas de mando del puente y de la sala de máquinas. La identidad visual debe transmitir: 1. **Confianza profesional** — esto no es un toy. Es un sistema crítico que mueve toneladas y combustible bajo presión. 2. **Calma de mar profundo** — la paleta default es oscura para no fatigar al operador en turnos largos de noche. 3. **Claridad inequívoca** — colores de alarma estandarizados (cerca de las prácticas IMO), tipografía técnica para valores. 4. **Personalidad** — sin ser un producto enterprise gris. Detalles de marca (compás, casco, glow cyan) le dan alma de "navegante". **No es:** ni industrial-feo (PLC años 90), ni consumer-juguete (apps fintech), ni nave-espacial fantasioso (sci-fi). **Sí es:** Lufthansa cockpit ↔ Tesla Roadster cabin ↔ B&G Vulcan plotter. --- ## 2. Paleta — VMS Ocean ### Modo oscuro (default) | Token | Hex | Uso | |---|---|---| | `--c-abyss` | `#04111F` | Background base del app, casi negro navy | | `--c-midnight` | `#0A1A2E` | Cards, paneles | | `--c-steel` | `#1A2B42` | Bordes, divisores, hover background | | `--c-iron` | `#2C3E5C` | Bordes activos, foreground muted | | `--c-fog` | `#7C8B9F` | Texto secundario, iconos inactivos | | `--c-sand` | `#E6EAF0` | Texto primario sobre dark | | `--c-foam` | `#F2F5F9` | Texto alta jerarquía, headlines | | `--c-cyan` | `#00D9FF` | **Accent primario** — marca, links, actividad | | `--c-cyan-deep` | `#1B7FB5` | Cyan profundo para gradientes | | `--c-horizon` | `#5BC0EB` | Accent secundario, gauges | ### Estado / semántico | Token | Hex | Uso | |---|---|---| | `--c-ok` | `#00E08A` | Estados OK, valores en rango | | `--c-info` | `#5BC0EB` | Alarma INFO | | `--c-warn` | `#FFB020` | Alarma LOW + WARNING (ámbar IMO) | | `--c-high` | `#FF8030` | Alarma HIGH (naranja escalada) | | `--c-emergency` | `#FF3B47` | Alarma EMERGENCY (rojo SOS) | | `--c-emergency-deep` | `#A11220` | Reset emergencia hover/active | ### Modo claro (alternativo "outdoor") Sólo para uso bajo sol fuerte en cubierta. Mismos accent colors, fondos invertidos. | Token | Hex | Uso | |---|---|---| | `--c-foam-light` | `#FFFFFF` | Background base | | `--c-sand-light` | `#F2F5F9` | Cards | | `--c-iron-light` | `#D1D8E0` | Bordes | | `--c-abyss-light` | `#04111F` | Texto primario | | `--c-fog-light` | `#5A6B7F` | Texto secundario | --- ## 3. Gradientes | Token | CSS | Uso | |---|---|---| | `--g-deep-sea` | `linear-gradient(135deg, #04111F 0%, #0A1A2E 60%, #1A2B42 100%)` | Background app | | `--g-horizon` | `linear-gradient(180deg, #04111F 0%, #1B3E6E 60%, #3A6BA8 90%, #5BC0EB 100%)` | Hero, splash | | `--g-cyan-glow` | `radial-gradient(circle at 50% 50%, rgba(0,217,255,0.4) 0%, transparent 70%)` | Aura tras logo | | `--g-glass` | `linear-gradient(135deg, rgba(255,255,255,0.06), rgba(255,255,255,0.02))` | Glassmorphism cards | | `--g-glass-edge` | `linear-gradient(135deg, rgba(255,255,255,0.18), rgba(255,255,255,0.02))` | Borde 1px de glass | | `--g-emergency` | `linear-gradient(135deg, #FF3B47, #A11220)` | Botón emergency | | `--g-cyan` | `linear-gradient(135deg, #00D9FF 0%, #5BC0EB 50%, #1B7FB5 100%)` | Logo, accent fill | --- ## 4. Tipografía ### Familia | Rol | Familia | Fallback | |---|---|---| | Display (H1, splash, branding) | **Space Grotesk** | `Inter, system-ui, sans-serif` | | UI / cuerpo | **Inter** | `system-ui, -apple-system, "Segoe UI", Roboto, sans-serif` | | Valores numéricos / mono | **JetBrains Mono** | `"Cascadia Mono", Consolas, "Courier New", monospace` | ### Escalas (modo dark, sobre `--c-abyss`) | Token | Size | Line-height | Weight | Letter-spacing | Color | |---|---|---|---|---|---| | `--t-display-xl` | 56px | 1.05 | 700 | -1.5px | `--c-foam` | | `--t-display-lg` | 40px | 1.1 | 700 | -1.0px | `--c-foam` | | `--t-h1` | 32px | 1.2 | 600 | -0.5px | `--c-foam` | | `--t-h2` | 24px | 1.25 | 600 | -0.3px | `--c-foam` | | `--t-h3` | 18px | 1.35 | 600 | -0.2px | `--c-sand` | | `--t-body-lg` | 16px | 1.5 | 400 | 0 | `--c-sand` | | `--t-body` | 14px | 1.5 | 400 | 0 | `--c-sand` | | `--t-caption` | 12px | 1.4 | 500 | 0.4px | `--c-fog` | | `--t-overline` | 11px | 1.2 | 600 | 2.4px (uppercase) | `--c-fog` | | `--t-value-xl` | 48px | 1.0 | 600 | -1.5px | `--c-foam` (mono) | | `--t-value-lg` | 28px | 1.0 | 500 | -0.5px | `--c-foam` (mono) | | `--t-value` | 16px | 1.0 | 500 | 0 | `--c-sand` (mono) | ### Tono y estilo del copy - **Español por defecto** (regla de oro #13) - **Verbos en imperativo** para botones: "Acuse recibo", "Reset emergencia" - **Sin exclamaciones**. Esto es industrial, no Black Friday - **Valores con unidad SI siempre adyacente**: `87.2 bar`, `1450 rpm` - **Timestamps en ISO local**: `2026-05-17 03:42:18` --- ## 5. Espaciado Sistema base de **4px**. Tokens: | Token | px | Uso típico | |---|---|---| | `--s-0` | 0 | reset | | `--s-1` | 4 | gap interno mínimo | | `--s-2` | 8 | padding small | | `--s-3` | 12 | gap cards | | `--s-4` | 16 | padding default | | `--s-5` | 24 | sección | | `--s-6` | 32 | bloques | | `--s-7` | 48 | hero | | `--s-8` | 64 | grandes layouts | | `--s-9` | 96 | splash | --- ## 6. Border-radius | Token | px | Uso | |---|---|---| | `--r-1` | 4 | inputs, chips small | | `--r-2` | 8 | botones default | | `--r-3` | 12 | cards | | `--r-4` | 16 | paneles grandes | | `--r-5` | 24 | hero, modals | | `--r-pill` | 9999 | badges, switches | --- ## 7. Sombras y elevación 5 niveles de elevación + 2 efectos especiales: | Token | CSS | |---|---| | `--e-1` | `0 1px 3px rgba(0,0,0,0.32)` | | `--e-2` | `0 4px 12px rgba(0,0,0,0.40)` | | `--e-3` | `0 8px 24px rgba(0,0,0,0.50)` | | `--e-4` | `0 16px 48px rgba(0,0,0,0.60)` | | `--e-5` (modal) | `0 32px 80px rgba(0,0,0,0.70)` | | `--glow-cyan` | `0 0 24px rgba(0,217,255,0.45)` | | `--glow-warn` | `0 0 24px rgba(255,176,32,0.45)` | | `--glow-emergency` | `0 0 32px rgba(255,59,71,0.55)` | | `--inner-stroke` | `inset 0 0 0 1px rgba(255,255,255,0.06)` | --- ## 8. Glassmorphism Para paneles superpuestos (notificaciones, dropdowns, modales sobre mímicos): ```css background: var(--g-glass); border: 1px solid rgba(255,255,255,0.08); backdrop-filter: blur(16px) saturate(1.4); box-shadow: var(--e-3), var(--inner-stroke); ``` **Uso prudente.** No abusar — los mímicos críticos deben ser sólidos para lecturabilidad. --- ## 9. Iconografía - **Estilo**: 2px stroke, esquinas redondeadas (1px radius), 24×24px canvas base - **Familia base**: Lucide / Phosphor (libres). Custom para símbolos navales (válvulas ISO 14617, motor, bomba, intercambiador, etc.) - **Color**: `currentColor` para que herede del contexto - **Inactivos**: opacity 0.5 --- ## 10. Componentes clave ### Botones | Variante | Background | Border | Color | Sombra | |---|---|---|---|---| | Primary | `--g-cyan` | none | `#04111F` | `--glow-cyan` | | Secondary | transparent | `1px solid --c-iron` | `--c-sand` | none | | Ghost | transparent | none | `--c-cyan` | none | | Danger | `--g-emergency` | none | `--c-foam` | `--glow-emergency` | | Disabled | `--c-steel` | none | `--c-fog` | none | Padding: `12px 20px` default. Min-width 96px. Border-radius `--r-2`. ### Cards / Paneles ```css background: var(--c-midnight); border: 1px solid var(--c-steel); border-radius: var(--r-3); padding: var(--s-5); box-shadow: var(--e-2); ``` ### Badges de prioridad de alarma | Prioridad | Background | Color | Border | |---|---|---|---| | EMERGENCY | `#FF3B47` | `#FFFFFF` | inset 0 0 0 1px #FF8090 | | HIGH | `#FF8030` | `#04111F` | inset 0 0 0 1px #FFA060 | | LOW | `#FFB020` | `#04111F` | inset 0 0 0 1px #FFCB60 | | INFO | `#5BC0EB` | `#04111F` | inset 0 0 0 1px #8DDBF2 | Forma pill (`border-radius: --r-pill`), uppercase, letter-spacing 0.5px, padding `4px 10px`. ### Gauges (visión general) - Bar gauge horizontal: ancho variable, alto 8-12px, fondo `--c-steel`, fill con `--g-cyan` o color de estado - Arc gauge: 220° arc, stroke 8px, valor central en `--t-value-xl` mono - Donut: 100% completo, fill por segmentos con colores semánticos ### Indicador Roll/Pitch (Trim panel) - Pantalla negra circular con grilla de horizonte - Línea de horizonte animada que rota según roll - Marcas cada 5°, números cada 10° - Bandas de color: -8°a +8° (`--c-ok`), 8°-12° (`--c-warn`), 12°-18° (`--c-high`), >18° (`--c-emergency`) - Glow del color de estado activo --- ## 11. Motion principles | Acción | Duration | Easing | |---|---|---| | Hover/focus | 120ms | `cubic-bezier(0.4, 0, 0.2, 1)` | | Entrada de elemento | 240ms | `cubic-bezier(0.0, 0, 0.2, 1)` (ease-out) | | Salida | 200ms | `cubic-bezier(0.4, 0, 1, 1)` (ease-in) | | Modal | 280ms | `cubic-bezier(0.4, 0, 0.2, 1)` | | Alarma crítica entry | 320ms | `cubic-bezier(0.34, 1.56, 0.64, 1)` (bounce sutil) | | Roll/pitch indicator | live | damped, sin animation (refresh ≤100ms) | | Pulse de alarma activa | 1200ms | `ease-in-out` infinite | **Sin animaciones decorativas en valores críticos.** El RPM no "se anima" de 1200 a 1450 — salta. La animación introduce delay perceptivo. --- ## 12. Layout patterns ### Studio shell (Sprint 1) ``` ┌────────────────────────────────────────────────────────────┐ │ topbar: logo · proyecto activo · acciones │ 48px ├──────────┬─────────────────────────────────────┬───────────┤ │ sidebar │ │ inspector │ │ (sistemas)│ canvas central │ (props) │ │ 256px │ (silueta + mímico) │ 320px │ │ │ │ │ ├──────────┴─────────────────────────────────────┴───────────┤ │ statusbar: cobertura tests · version · sprint │ 32px └────────────────────────────────────────────────────────────┘ ``` ### Runtime cliente (Sprint 6) ``` ┌────────────────────────────────────────────────────────────┐ │ vessel name · status · alarms badge · authority · user │ 56px ├──────────┬─────────────────────────────────────────────────┤ │ system │ │ │ sidebar │ active view: overview | mimic | alarms | │ │ 240px │ trends | trim | logbook | audit │ │ │ │ ├──────────┴─────────────────────────────────────────────────┤ │ ticker alarmas · hora · VPN status │ 32px └────────────────────────────────────────────────────────────┘ ``` ### Mobile (Sprint 11) - Bottom tab nav: Overview · Mímicos · Alarmas · Trim · Más - Top bar mínima con nombre del buque y alarma count - Single-column layout, swipe gestures --- ## 13. Accesibilidad - Contraste mínimo WCAG **AA** (4.5:1 texto, 3:1 large). El amber sobre navy lo cumple. - Touch targets móviles: **44×44pt iOS / 48×48dp Android** mínimo - Estados de focus visibles: outline 2px `--c-cyan` + offset 2px - Color **nunca** como único indicador — siempre acompañado por ícono o texto --- ## 14. Don't list - ❌ Sin "neon glow" excesivo — sólo en logo y elementos de marca - ❌ Sin emojis en UI — son ambiguos visualmente para alarmas - ❌ Sin animaciones decorativas en valores críticos - ❌ Sin gradientes en texto pequeño (lecturabilidad pobre) - ❌ Sin fuentes serif — no encaja con el carácter técnico - ❌ Sin scrollbars custom invasivos — respetar plataforma - ❌ Sin tooltips obligatorios para entender la UI — diseña explícito --- ## 15. Mockups de referencia | Archivo | Descripción | |---|---| | `docs/mockups/splash.html` | Pantalla de bienvenida con logo + tagline | | `docs/mockups/studio_main.html` | Studio (Sprint 1) — wizard + canvas | | `docs/mockups/runtime_overview.html` | Dashboard del buque (Sprint 6) | | `docs/mockups/runtime_mimic_fuel.html` | Mímico sistema combustible | | `docs/mockups/runtime_alarms.html` | Panel de alarmas | | `docs/mockups/runtime_trim.html` | Trim & Maniobra (panel destacado) | | `docs/mockups/mobile_overview.html` | App móvil overview | | `docs/mockups/mobile_trim.html` | App móvil trim | Todos son HTML+CSS estáticos. Abrir directamente en navegador. --- ## 16. Brand assets (`docs/brand/`) | Archivo | Uso | |---|---| | `logo.svg` | Horizontal completo (320×80), color | | `logo-mark.svg` | Solo compass mark (96×96), color | | `logo-mono.svg` | Horizontal monocromático (`currentColor`) | | `favicon.svg` | Cuadrado 64×64 con fondo navy | --- **Versión 1.0 — Sprint 0.** Cambios mayores requieren acuerdo explícito de Álvaro (es la base visual de todo el producto).