Files
AR-VMS-Seaman/docs/mockups/studio_main.html
T
alro65 deb04c9315 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>
2026-05-17 07:26:06 -04:00

443 lines
19 KiB
HTML

<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>VMS-Sailor Studio · Mockup Sprint 1</title>
<link rel="icon" type="image/svg+xml" href="../brand/favicon.svg">
<link rel="stylesheet" href="_tokens.css">
<style>
body { overflow: hidden; }
.studio {
display: grid;
grid-template-rows: 56px 1fr 32px;
grid-template-columns: 280px 1fr 340px;
grid-template-areas:
"topbar topbar topbar"
"sidebar canvas inspector"
"statusbar statusbar statusbar";
height: 100vh;
}
/* Topbar */
.topbar {
grid-area: topbar;
display: flex;
align-items: center;
gap: var(--s-5);
padding: 0 var(--s-5);
background: var(--c-midnight);
border-bottom: 1px solid var(--c-steel);
}
.topbar img { height: 32px; }
.breadcrumb {
display: flex; align-items: center; gap: var(--s-3);
font-size: 13px; color: var(--c-fog);
}
.breadcrumb .sep { opacity: 0.5; }
.breadcrumb strong { color: var(--c-sand); font-weight: 600; }
.breadcrumb .active { color: var(--c-cyan); font-weight: 600; }
.topbar-spacer { flex: 1; }
.topbar-actions { display: flex; gap: var(--s-2); align-items: center; }
/* Sidebar */
.sidebar {
grid-area: sidebar;
background: var(--c-midnight);
border-right: 1px solid var(--c-steel);
overflow-y: auto;
padding: var(--s-4) 0;
}
.sb-section { padding: var(--s-3) var(--s-4); }
.sb-title {
display: flex; align-items: center; justify-content: space-between;
font-size: 11px; font-weight: 700; letter-spacing: 2px;
color: var(--c-fog); text-transform: uppercase;
margin-bottom: var(--s-2);
}
.sb-tree { list-style: none; padding: 0; margin: 0; }
.sb-tree li {
padding: 8px 12px; border-radius: var(--r-2);
display: flex; align-items: center; gap: var(--s-2);
color: var(--c-sand); font-size: 13px;
cursor: pointer;
transition: background 120ms var(--ease-standard);
}
.sb-tree li:hover { background: var(--c-steel); }
.sb-tree li.active {
background: linear-gradient(90deg, rgba(0,217,255,0.12), transparent);
color: var(--c-foam);
box-shadow: inset 2px 0 0 var(--c-cyan);
}
.sb-tree .count {
margin-left: auto;
font-family: var(--f-mono);
font-size: 11px;
color: var(--c-fog);
background: var(--c-steel);
padding: 2px 6px;
border-radius: var(--r-pill);
}
/* Canvas */
.canvas {
grid-area: canvas;
position: relative;
background:
radial-gradient(circle at 50% 50%, rgba(0,217,255,0.06) 0%, transparent 70%),
var(--g-deep-sea);
overflow: hidden;
}
.canvas-grid {
position: absolute; inset: 0;
background-image:
linear-gradient(rgba(91,192,235,0.06) 1px, transparent 1px),
linear-gradient(90deg, rgba(91,192,235,0.06) 1px, transparent 1px);
background-size: 40px 40px;
}
.canvas-toolbar {
position: absolute;
top: var(--s-4); left: var(--s-4);
display: flex; gap: var(--s-2);
padding: var(--s-2);
background: var(--g-glass);
border: 1px solid rgba(255,255,255,0.08);
border-radius: var(--r-3);
backdrop-filter: blur(16px);
}
.vessel-stage {
position: absolute; inset: 0;
display: flex; align-items: center; justify-content: center;
}
.vessel-svg {
width: min(90%, 900px);
filter: drop-shadow(0 12px 32px rgba(0,217,255,0.18));
}
.coord-label {
position: absolute;
font-family: var(--f-mono);
font-size: 10px;
color: var(--c-fog);
letter-spacing: 1px;
}
.axis-x { bottom: var(--s-4); left: 50%; }
.axis-z { left: var(--s-4); top: 50%; transform: rotate(-90deg); transform-origin: left center; }
/* Equipment dots on canvas */
.eq-dot {
position: absolute;
width: 14px; height: 14px;
border-radius: 50%;
background: var(--c-cyan);
box-shadow: 0 0 0 4px rgba(0,217,255,0.18), var(--glow-cyan);
cursor: pointer;
}
.eq-tooltip {
position: absolute;
background: rgba(4,17,31,0.92);
border: 1px solid var(--c-iron);
border-radius: var(--r-2);
padding: 8px 12px;
font-size: 12px;
pointer-events: none;
white-space: nowrap;
}
.eq-tooltip strong { color: var(--c-cyan); display: block; margin-bottom: 2px; font-size: 11px; letter-spacing: 1px; text-transform: uppercase; }
.eq-tooltip span { color: var(--c-sand); font-family: var(--f-mono); }
/* Inspector */
.inspector {
grid-area: inspector;
background: var(--c-midnight);
border-left: 1px solid var(--c-steel);
overflow-y: auto;
padding: var(--s-5);
}
.insp-header {
display: flex; align-items: center; gap: var(--s-3);
margin-bottom: var(--s-5);
}
.insp-header h2 {
margin: 0;
font-family: var(--f-display);
font-size: 22px;
font-weight: 600;
color: var(--c-foam);
}
.insp-row {
display: grid;
grid-template-columns: 110px 1fr;
gap: var(--s-3);
padding: var(--s-3) 0;
border-bottom: 1px solid var(--c-steel);
font-size: 13px;
}
.insp-row:last-child { border-bottom: none; }
.insp-row .k { color: var(--c-fog); }
.insp-row .v { color: var(--c-foam); font-family: var(--f-mono); }
.insp-row .v.text { font-family: var(--f-ui); }
/* Statusbar */
.statusbar {
grid-area: statusbar;
display: flex;
align-items: center;
gap: var(--s-5);
padding: 0 var(--s-5);
background: var(--c-midnight);
border-top: 1px solid var(--c-steel);
font-family: var(--f-mono);
font-size: 11px;
color: var(--c-fog);
}
.statusbar .sep { color: var(--c-iron); }
.statusbar strong { color: var(--c-sand); }
.sb-spacer { flex: 1; }
/* Icons */
.ic { width: 16px; height: 16px; stroke-width: 2; stroke: currentColor; fill: none; }
</style>
</head>
<body>
<div class="app-root studio">
<header class="topbar">
<img src="../brand/logo.svg" alt="VMS-Sailor">
<div class="breadcrumb">
<span>Proyectos</span>
<span class="sep">/</span>
<strong>m_y_aurora_sunseeker_76</strong>
<span class="sep">/</span>
<span class="active">Topología</span>
</div>
<div class="topbar-spacer"></div>
<div class="topbar-actions">
<span class="chip"><span class="dot ok"></span> Sin cambios sin guardar</span>
<button class="btn-icon" title="Simulador">
<svg class="ic" viewBox="0 0 24 24"><polygon points="5 3 19 12 5 21 5 3"/></svg>
</button>
<button class="btn-icon" title="Validar">
<svg class="ic" viewBox="0 0 24 24"><path d="M9 12l2 2 4-4"/><circle cx="12" cy="12" r="9"/></svg>
</button>
<button class="btn btn-secondary">Compilar .vmspack</button>
<button class="btn btn-primary">Guardar</button>
</div>
</header>
<aside class="sidebar">
<div class="sb-section">
<div class="sb-title">
<span>Wizard</span>
<span style="color: var(--c-ok); font-weight: 700;">8/8</span>
</div>
<ul class="sb-tree">
<li><span class="dot ok"></span> 1. Tipo de buque</li>
<li><span class="dot ok"></span> 2. Plantilla</li>
<li><span class="dot ok"></span> 3. Dimensiones</li>
<li><span class="dot ok"></span> 4. Sistemas</li>
<li><span class="dot ok"></span> 5. Equipos sugeridos</li>
<li><span class="dot ok"></span> 6. Refinamiento</li>
<li class="active"><span class="dot cyan"></span> 7. Topología I/O</li>
<li><span class="dot"></span> 8. Confirmación</li>
</ul>
</div>
<div class="sb-section">
<div class="sb-title">
<span>Sistemas habilitados</span>
<span>14</span>
</div>
<ul class="sb-tree">
<li>⚙ Máquina principal <span class="count">2</span></li>
<li>⚡ Generadores <span class="count">1</span></li>
<li>🛡 Trim & Maniobra <span class="count">4</span></li>
<li>⛽ Combustible <span class="count">2</span></li>
<li>💧 Refrigeración <span class="count">2</span></li>
<li>🔥 Sentinas <span class="count">3</span></li>
<li>🌬 HVAC <span class="count">1</span></li>
<li>🔆 Iluminación <span class="count">5</span></li>
<li><em style="color: var(--c-fog);">+ 6 más…</em></li>
</ul>
</div>
</aside>
<main class="canvas">
<div class="canvas-grid"></div>
<div class="canvas-toolbar">
<button class="btn-icon" title="Zoom in"><svg class="ic" viewBox="0 0 24 24"><circle cx="11" cy="11" r="7"/><line x1="11" y1="8" x2="11" y2="14"/><line x1="8" y1="11" x2="14" y2="11"/></svg></button>
<button class="btn-icon" title="Zoom out"><svg class="ic" viewBox="0 0 24 24"><circle cx="11" cy="11" r="7"/><line x1="8" y1="11" x2="14" y2="11"/></svg></button>
<button class="btn-icon" title="Centrar"><svg class="ic" viewBox="0 0 24 24"><circle cx="12" cy="12" r="3"/><path d="M12 3v3M12 18v3M3 12h3M18 12h3"/></svg></button>
<button class="btn-icon" title="Mostrar tarjetas"><svg class="ic" viewBox="0 0 24 24"><rect x="3" y="6" width="18" height="12" rx="2"/><line x1="3" y1="10" x2="21" y2="10"/></svg></button>
</div>
<div class="vessel-stage">
<svg class="vessel-svg" viewBox="0 0 900 380" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="hull" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stop-color="#E6EAF0"/>
<stop offset="100%" stop-color="#5A6B7F"/>
</linearGradient>
<linearGradient id="superstructure" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stop-color="#F2F5F9"/>
<stop offset="100%" stop-color="#94A3B8"/>
</linearGradient>
<linearGradient id="water" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stop-color="rgba(0,217,255,0.18)"/>
<stop offset="100%" stop-color="rgba(0,217,255,0)"/>
</linearGradient>
</defs>
<!-- Waterline reflection -->
<rect x="0" y="260" width="900" height="120" fill="url(#water)"/>
<!-- Silhouette: Sunseeker 76 side view, simplified -->
<!-- Hull -->
<path d="M 80 240 Q 60 200 130 175 L 720 175 Q 800 175 820 215 L 815 255 Q 800 280 760 280 L 200 280 Q 110 280 80 240 Z"
fill="url(#hull)" stroke="#04111F" stroke-width="1.5"/>
<!-- Superstructure -->
<path d="M 230 175 L 250 130 L 580 130 L 640 175 Z"
fill="url(#superstructure)" stroke="#04111F" stroke-width="1.5"/>
<!-- Flybridge -->
<path d="M 360 130 L 380 100 L 520 100 L 540 130 Z"
fill="url(#superstructure)" stroke="#04111F" stroke-width="1.2"/>
<!-- Windows -->
<rect x="280" y="142" width="280" height="20" rx="3" fill="#04111F" opacity="0.7"/>
<!-- Mast -->
<line x1="450" y1="100" x2="450" y2="60" stroke="#7C8B9F" stroke-width="2"/>
<circle cx="450" cy="60" r="3" fill="#00D9FF"/>
<!-- Waterline -->
<line x1="60" y1="260" x2="830" y2="260" stroke="#00D9FF" stroke-width="1" stroke-dasharray="6 6" opacity="0.6"/>
<!-- Bulkheads -->
<line x1="320" y1="175" x2="320" y2="270" stroke="#00D9FF" stroke-width="1" stroke-dasharray="3 3" opacity="0.4"/>
<line x1="540" y1="175" x2="540" y2="270" stroke="#00D9FF" stroke-width="1" stroke-dasharray="3 3" opacity="0.4"/>
<line x1="690" y1="175" x2="690" y2="270" stroke="#00D9FF" stroke-width="1" stroke-dasharray="3 3" opacity="0.4"/>
<!-- Coord ticks -->
<g font-family="JetBrains Mono, monospace" font-size="9" fill="#7C8B9F">
<text x="780" y="298">x_pp 0</text>
<text x="80" y="298">x_pp 23.5 m</text>
</g>
<!-- Equipment dots overlaid via SVG -->
<g>
<circle cx="250" cy="240" r="7" fill="#00D9FF" stroke="#04111F" stroke-width="2"/>
<circle cx="250" cy="240" r="13" fill="none" stroke="rgba(0,217,255,0.4)" stroke-width="2"/>
<text x="248" y="312" font-family="Inter" font-size="10" fill="#E6EAF0" text-anchor="middle">ME_PORT</text>
<circle cx="320" cy="240" r="7" fill="#00D9FF" stroke="#04111F" stroke-width="2"/>
<circle cx="320" cy="240" r="13" fill="none" stroke="rgba(0,217,255,0.4)" stroke-width="2"/>
<text x="318" y="328" font-family="Inter" font-size="10" fill="#E6EAF0" text-anchor="middle">ME_STBD</text>
<circle cx="400" cy="240" r="7" fill="#FFB020" stroke="#04111F" stroke-width="2"/>
<text x="400" y="312" font-family="Inter" font-size="10" fill="#FFB020" text-anchor="middle">GEN_1</text>
<circle cx="610" cy="225" r="6" fill="#5BC0EB" stroke="#04111F" stroke-width="2"/>
<text x="610" y="312" font-family="Inter" font-size="10" fill="#E6EAF0" text-anchor="middle">TANK_FUEL_1</text>
<circle cx="660" cy="245" r="6" fill="#5BC0EB" stroke="#04111F" stroke-width="2"/>
<text x="660" y="328" font-family="Inter" font-size="10" fill="#E6EAF0" text-anchor="middle">TANK_FUEL_2</text>
<circle cx="180" cy="245" r="5" fill="#00E08A" stroke="#04111F" stroke-width="2"/>
<text x="180" y="312" font-family="Inter" font-size="10" fill="#E6EAF0" text-anchor="middle">BILGE_AFT</text>
<circle cx="500" cy="245" r="5" fill="#00E08A" stroke="#04111F" stroke-width="2"/>
<text x="500" y="312" font-family="Inter" font-size="10" fill="#E6EAF0" text-anchor="middle">BILGE_MID</text>
<circle cx="730" cy="220" r="5" fill="#00E08A" stroke="#04111F" stroke-width="2"/>
<text x="730" y="312" font-family="Inter" font-size="10" fill="#E6EAF0" text-anchor="middle">BILGE_FWD</text>
</g>
<!-- Card highlight -->
<g>
<rect x="240" y="220" width="100" height="40" rx="6" fill="none" stroke="#00D9FF" stroke-width="2" stroke-dasharray="4 4" opacity="0.8"/>
<text x="290" y="216" font-family="Inter" font-size="10" font-weight="700" fill="#00D9FF" text-anchor="middle">CARD_001 · slot 1 · addr 1</text>
</g>
</svg>
</div>
</main>
<aside class="inspector">
<div class="insp-header">
<div style="width:36px; height:36px; border-radius: var(--r-2); background: var(--g-cyan); display:flex; align-items:center; justify-content:center;">
<svg class="ic" viewBox="0 0 24 24" style="color:#04111F"><rect x="3" y="6" width="18" height="12" rx="2"/><line x1="3" y1="10" x2="21" y2="10"/></svg>
</div>
<div>
<h2>CARD_001</h2>
<span class="caption">AR-NMEA-IO-v1.0 · slot 1</span>
</div>
</div>
<div>
<div class="insp-row"><span class="k">Serial</span><span class="v">ARC-2026-00153</span></div>
<div class="insp-row"><span class="k">Bus</span><span class="v">bus_main</span></div>
<div class="insp-row"><span class="k">Rol</span><span class="v">MODBUS_SLAVE</span></div>
<div class="insp-row"><span class="k">Modbus addr</span><span class="v">1</span></div>
<div class="insp-row"><span class="k">Ubicación</span><span class="v text">SM panel ME_PORT</span></div>
<div class="insp-row"><span class="k">x_pp</span><span class="v">5.50 m</span></div>
<div class="insp-row"><span class="k">y_cl</span><span class="v">-0.50 m</span></div>
<div class="insp-row"><span class="k">z_bl</span><span class="v">+1.40 m</span></div>
<div class="insp-row"><span class="k">Firmware</span><span class="v">1.4.2</span></div>
</div>
<div style="margin-top: var(--s-5);">
<div class="sb-title" style="padding: 0; color: var(--c-fog);">Capacidad usada</div>
<div style="display: grid; gap: var(--s-2); margin-top: var(--s-2); font-family: var(--f-mono); font-size: 12px;">
<div style="display: flex; justify-content: space-between;">
<span>DO</span><span><strong style="color:var(--c-foam)">2</strong>/10 <span style="color:var(--c-fog)">· 20%</span></span>
</div>
<div style="height: 6px; background: var(--c-steel); border-radius: var(--r-pill);">
<div style="width: 20%; height: 100%; background: var(--g-cyan); border-radius: var(--r-pill);"></div>
</div>
<div style="display: flex; justify-content: space-between;">
<span>DI</span><span><strong style="color:var(--c-foam)">2</strong>/5 <span style="color:var(--c-fog)">· 40%</span></span>
</div>
<div style="height: 6px; background: var(--c-steel); border-radius: var(--r-pill);">
<div style="width: 40%; height: 100%; background: var(--g-cyan); border-radius: var(--r-pill);"></div>
</div>
<div style="display: flex; justify-content: space-between;">
<span>AI</span><span><strong style="color:var(--c-foam)">4</strong>/4 <span style="color:var(--c-warn)">· 100%</span></span>
</div>
<div style="height: 6px; background: var(--c-steel); border-radius: var(--r-pill);">
<div style="width: 100%; height: 100%; background: var(--g-warn); border-radius: var(--r-pill);"></div>
</div>
<div style="display: flex; justify-content: space-between;">
<span>RPM</span><span><strong style="color:var(--c-foam)">1</strong>/1 <span style="color:var(--c-warn)">· 100%</span></span>
</div>
<div style="height: 6px; background: var(--c-steel); border-radius: var(--r-pill);">
<div style="width: 100%; height: 100%; background: var(--g-warn); border-radius: var(--r-pill);"></div>
</div>
</div>
</div>
<div style="margin-top: var(--s-5);">
<button class="btn btn-secondary" style="width: 100%; margin-bottom: var(--s-2);">Editar bindings</button>
<button class="btn btn-ghost" style="width: 100%;">Ver puertos físicos →</button>
</div>
</aside>
<footer class="statusbar">
<span><strong>14</strong> sistemas</span>
<span class="sep">|</span>
<span><strong>3</strong> equipos</span>
<span class="sep">|</span>
<span><strong>11</strong> tags</span>
<span class="sep">|</span>
<span><strong>3</strong> tarjetas</span>
<span class="sep">|</span>
<span>tests <strong style="color:var(--c-ok)">99/99</strong></span>
<span class="sep">|</span>
<span>cov <strong style="color:var(--c-ok)">95.17%</strong></span>
<span class="sb-spacer"></span>
<span>VMS-Sailor Studio <strong>0.1.0</strong></span>
<span class="sep">|</span>
<span>Sprint <strong style="color:var(--c-cyan)">0</strong></span>
<span class="sep">|</span>
<span><span class="dot ok"></span> Activado</span>
</footer>
</div>
</body>
</html>