deb04c9315
Sprint 0 completo del producto VMS-Sailor (Vessel Management System integrado para buques 30-40m). Brief de referencia en VMS_Sailor_v2_Parte_*.md (intacto). Core (vmssailor.core, 95.17% coverage, 99 tests verde): - ShipCoord: sistema naval x_pp/y_cl/z_bl frozen - Vessel, Deck, Bulkhead - Equipment, EquipmentModel, Sensor, EquipmentSpec - Tag, AlarmConfig, TagBinding, Scaling - CardInstance, Bus, Topology con validacion 21 puntos I/O AR-NMEA-IO-v1.0 - Alarm, PermissiveRule, Condition - Project agregado raiz con validacion cross-entity - Persistencia portable .vmsproj (SQLite) con roundtrip verificable Biblioteca curada seed (vmssailor.library): - systems_catalog.json completo (catalogo maestro Parte 1 sec 7) - 2 vessels: Sunseeker 76, Ferretti 850 - 2 motores: MTU 12V 2000 M96, Volvo D13-900 - 1 genset: Northern Lights M65C13 - yacht_motor_planeo.yaml (reglas heuristicas) - TODO marcado data_source=seed_estimate - requiere validacion datasheets Tools: - vms-validate-library: CLI valida biblioteca completa - vms-generate-test-project: CLI demo + verificacion roundtrip persistencia Design System + 8 mockups HTML estaticos: - docs/design_system.md (paleta Deep Ocean, gradientes, typography, motion) - docs/brand/ (logo + variantes SVG) - docs/mockups/splash, studio_main, runtime_overview, runtime_mimic_fuel (P&ID animado), runtime_alarms, runtime_trim (panel estrella con horizonte artificial), mobile_overview, mobile_trim - docs/mockups/index.html (galeria) Firmware (Sprint 12+ implementacion): - firmware/ar_nmea_io_v1/src/config/pinout.h con macros GPIO Decisiones autonomas documentadas en docs/decisions_sprint0.md. Stack: Python 3.11 + uv + Pydantic v2 + SQLite stdlib + hatchling + pytest 9 + ruff + mypy. Sin PySide6, FastAPI, Flutter ni firmware funcional (entran en sprints siguientes). Criterio de aceptacion Sprint 0: cumplido. - uv sync: OK - pytest: 99/99 verde - cov vmssailor.core: 95.17% (objetivo >=80%) - ruff: clean - vms-validate-library: OK - vms-generate-test-project: INTEGRIDAD OK Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
370 lines
14 KiB
Markdown
370 lines
14 KiB
Markdown
# 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).
|