sprint-0: fundaciones VMS-Sailor

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>
This commit is contained in:
2026-05-17 07:26:06 -04:00
commit deb04c9315
96 changed files with 15335 additions and 0 deletions
+369
View File
@@ -0,0 +1,369 @@
# 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).