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>
549 lines
25 KiB
HTML
549 lines
25 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 · Mímico Combustible</title>
|
||
<link rel="icon" type="image/svg+xml" href="../brand/favicon.svg">
|
||
<link rel="stylesheet" href="_tokens.css">
|
||
<style>
|
||
body { overflow: hidden; }
|
||
.rt {
|
||
display: grid;
|
||
grid-template-rows: 56px 1fr 32px;
|
||
grid-template-columns: 240px 1fr 320px;
|
||
grid-template-areas:
|
||
"topbar topbar topbar"
|
||
"sidebar canvas inspector"
|
||
"ticker ticker ticker";
|
||
height: 100vh;
|
||
}
|
||
.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);
|
||
}
|
||
.breadcrumb {
|
||
display: flex; align-items: center; gap: var(--s-3);
|
||
font-size: 13px;
|
||
color: var(--c-fog);
|
||
}
|
||
.breadcrumb img { height: 28px; }
|
||
.breadcrumb strong { color: var(--c-foam); font-family: var(--f-display); font-size: 16px; }
|
||
.breadcrumb .sep { opacity: 0.5; }
|
||
.breadcrumb .system { color: var(--c-cyan); font-weight: 600; }
|
||
.topbar .top-spacer { flex: 1; }
|
||
.topbar .actions { display: flex; gap: var(--s-2); align-items: center; }
|
||
|
||
.sidebar {
|
||
grid-area: sidebar;
|
||
background: var(--c-midnight);
|
||
border-right: 1px solid var(--c-steel);
|
||
padding: var(--s-4) 0;
|
||
overflow-y: auto;
|
||
}
|
||
.sb-title { font-size: 10px; font-weight: 700; letter-spacing: 2px;
|
||
color: var(--c-fog); text-transform: uppercase;
|
||
padding: var(--s-4) var(--s-4) var(--s-2); }
|
||
.nav-item {
|
||
display: flex; align-items: center; gap: var(--s-2);
|
||
padding: 10px 16px;
|
||
color: var(--c-sand); font-size: 13px;
|
||
cursor: pointer; transition: background 120ms;
|
||
}
|
||
.nav-item:hover { background: var(--c-steel); }
|
||
.nav-item.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);
|
||
}
|
||
|
||
/* Canvas mimic */
|
||
.canvas {
|
||
grid-area: canvas;
|
||
position: relative;
|
||
background:
|
||
radial-gradient(circle at 30% 20%, rgba(0,217,255,0.04), transparent 60%),
|
||
var(--c-abyss);
|
||
overflow: hidden;
|
||
}
|
||
.canvas-bg-grid {
|
||
position: absolute; inset: 0;
|
||
background-image:
|
||
linear-gradient(rgba(91,192,235,0.04) 1px, transparent 1px),
|
||
linear-gradient(90deg, rgba(91,192,235,0.04) 1px, transparent 1px);
|
||
background-size: 24px 24px;
|
||
}
|
||
.mimic-header {
|
||
position: absolute;
|
||
top: var(--s-4); left: var(--s-5);
|
||
z-index: 3;
|
||
}
|
||
.mimic-header h2 {
|
||
margin: 0;
|
||
font-family: var(--f-display);
|
||
font-size: 26px;
|
||
font-weight: 600;
|
||
color: var(--c-foam);
|
||
}
|
||
.mimic-header .sub {
|
||
font-size: 12px;
|
||
color: var(--c-fog);
|
||
letter-spacing: 1px;
|
||
}
|
||
.canvas-actions {
|
||
position: absolute;
|
||
top: var(--s-4); right: var(--s-5);
|
||
display: flex; gap: var(--s-2);
|
||
z-index: 3;
|
||
}
|
||
.legend {
|
||
position: absolute;
|
||
bottom: var(--s-5); left: var(--s-5);
|
||
padding: var(--s-3) var(--s-4);
|
||
background: var(--g-glass);
|
||
border: 1px solid rgba(255,255,255,0.08);
|
||
backdrop-filter: blur(12px);
|
||
border-radius: var(--r-3);
|
||
display: flex; gap: var(--s-5);
|
||
font-size: 11px;
|
||
color: var(--c-fog);
|
||
z-index: 3;
|
||
}
|
||
.legend .swatch {
|
||
display: inline-block; width: 10px; height: 10px;
|
||
border-radius: 2px;
|
||
margin-right: 6px;
|
||
vertical-align: middle;
|
||
}
|
||
|
||
.mimic-svg {
|
||
position: absolute;
|
||
inset: 80px 0 60px 0;
|
||
width: 100%; height: calc(100% - 140px);
|
||
}
|
||
|
||
.inspector {
|
||
grid-area: inspector;
|
||
background: var(--c-midnight);
|
||
border-left: 1px solid var(--c-steel);
|
||
padding: var(--s-5);
|
||
overflow-y: auto;
|
||
}
|
||
.insp-tag {
|
||
font-family: var(--f-mono);
|
||
font-size: 14px;
|
||
color: var(--c-cyan);
|
||
font-weight: 600;
|
||
margin-bottom: 2px;
|
||
}
|
||
.insp-name {
|
||
font-family: var(--f-display);
|
||
font-size: 22px;
|
||
font-weight: 600;
|
||
color: var(--c-foam);
|
||
margin: 0 0 var(--s-3);
|
||
}
|
||
.insp-value {
|
||
font-family: var(--f-mono);
|
||
font-size: 56px;
|
||
font-weight: 600;
|
||
color: var(--c-foam);
|
||
letter-spacing: -2px;
|
||
line-height: 1;
|
||
}
|
||
.insp-value .unit { font-size: 18px; color: var(--c-fog); margin-left: 6px; font-weight: 400; }
|
||
.insp-trend {
|
||
margin-top: var(--s-3);
|
||
height: 60px;
|
||
width: 100%;
|
||
}
|
||
.insp-row {
|
||
display: grid;
|
||
grid-template-columns: 110px 1fr;
|
||
gap: var(--s-3);
|
||
padding: var(--s-2) 0;
|
||
font-size: 13px;
|
||
border-bottom: 1px solid var(--c-steel);
|
||
}
|
||
.insp-row:last-child { border-bottom: none; }
|
||
.insp-row .k { color: var(--c-fog); }
|
||
.insp-row .v { font-family: var(--f-mono); color: var(--c-foam); }
|
||
|
||
.alarm-section {
|
||
margin-top: var(--s-4);
|
||
padding: var(--s-3);
|
||
background: rgba(255,176,32,0.06);
|
||
border: 1px solid rgba(255,176,32,0.25);
|
||
border-radius: var(--r-2);
|
||
}
|
||
.alarm-section .ttl { font-size: 11px; letter-spacing: 1.5px; color: var(--c-warn); font-weight: 700; text-transform: uppercase; }
|
||
|
||
/* Flow animations */
|
||
@keyframes flowDash { to { stroke-dashoffset: -40; } }
|
||
.flow { stroke-dasharray: 8 8; animation: flowDash 1.6s linear infinite; }
|
||
.flow.fast { animation-duration: 0.8s; }
|
||
|
||
@keyframes pumpSpin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
|
||
.pump-rotor { animation: pumpSpin 0.7s linear infinite; transform-origin: center; transform-box: fill-box; }
|
||
|
||
.ticker {
|
||
grid-area: ticker;
|
||
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);
|
||
}
|
||
.ticker .sep { color: var(--c-iron); }
|
||
.ticker .pulse {
|
||
width: 8px; height: 8px;
|
||
border-radius: 50%;
|
||
background: var(--c-ok);
|
||
box-shadow: 0 0 12px rgba(0,224,138,0.7);
|
||
animation: heartbeat 2s ease-in-out infinite;
|
||
}
|
||
@keyframes heartbeat {
|
||
0%, 100% { transform: scale(1); opacity: 1; }
|
||
50% { transform: scale(1.4); opacity: 0.6; }
|
||
}
|
||
.tk-spacer { flex: 1; }
|
||
.ic { width: 16px; height: 16px; stroke: currentColor; fill: none; stroke-width: 2; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="app-root rt">
|
||
|
||
<header class="topbar">
|
||
<div class="breadcrumb">
|
||
<img src="../brand/logo-mark.svg" alt="">
|
||
<strong>M/Y Aurora</strong>
|
||
<span class="sep">/</span>
|
||
<span>Mímicos</span>
|
||
<span class="sep">/</span>
|
||
<span class="system">Combustible</span>
|
||
</div>
|
||
<span class="top-spacer"></span>
|
||
<span class="chip"><span class="dot ok"></span> 6 tags · 4 OK · 1 watch · 0 alarmas</span>
|
||
<span class="chip">Autoridad: <strong style="color:var(--c-cyan);margin-left:4px;">MÁQUINAS</strong></span>
|
||
<div class="actions">
|
||
<button class="btn-icon" title="Pausa updates"><svg class="ic" viewBox="0 0 24 24"><rect x="6" y="4" width="4" height="16"/><rect x="14" y="4" width="4" height="16"/></svg></button>
|
||
<button class="btn btn-secondary">Trends</button>
|
||
</div>
|
||
</header>
|
||
|
||
<aside class="sidebar">
|
||
<div class="sb-title">Sistemas</div>
|
||
<div class="nav-item">⚙ Máquina principal</div>
|
||
<div class="nav-item">⚡ Generación</div>
|
||
<div class="nav-item active">⛽ Combustible</div>
|
||
<div class="nav-item">💧 Refrigeración FW</div>
|
||
<div class="nav-item">🌊 Refrigeración SW</div>
|
||
<div class="nav-item">🛁 Sentinas</div>
|
||
<div class="nav-item">💨 Aire arranque</div>
|
||
<div class="nav-item">🌬 HVAC</div>
|
||
<div class="nav-item">💡 Iluminación</div>
|
||
<div class="sb-title">Combustible</div>
|
||
<div class="nav-item">📋 Resumen sistema</div>
|
||
<div class="nav-item">🔄 Transferencia tanques</div>
|
||
<div class="nav-item">🧪 Calidad y filtros</div>
|
||
<div class="nav-item">📊 Consumo histórico</div>
|
||
</aside>
|
||
|
||
<main class="canvas">
|
||
<div class="canvas-bg-grid"></div>
|
||
|
||
<div class="mimic-header">
|
||
<h2>Sistema de combustible</h2>
|
||
<div class="sub">2 tanques estructurales · 2 motores principales · 1 genset · Diesel marino MDO</div>
|
||
</div>
|
||
|
||
<div class="canvas-actions">
|
||
<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="Imprimir P&ID"><svg class="ic" viewBox="0 0 24 24"><polyline points="6 9 6 2 18 2 18 9"/><path d="M6 18H4a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2"/><rect x="6" y="14" width="12" height="8"/></svg></button>
|
||
<button class="btn btn-secondary">Calidad de filtros</button>
|
||
</div>
|
||
|
||
<svg class="mimic-svg" viewBox="0 0 1100 680" preserveAspectRatio="xMidYMid meet" xmlns="http://www.w3.org/2000/svg">
|
||
<defs>
|
||
<linearGradient id="tank" x1="0" y1="0" x2="0" y2="1">
|
||
<stop offset="0%" stop-color="#0A1A2E"/>
|
||
<stop offset="100%" stop-color="#1A2B42"/>
|
||
</linearGradient>
|
||
<linearGradient id="fuelFill" x1="0" y1="0" x2="0" y2="1">
|
||
<stop offset="0%" stop-color="#1B7FB5"/>
|
||
<stop offset="100%" stop-color="#00D9FF"/>
|
||
</linearGradient>
|
||
<linearGradient id="fuelFill2" x1="0" y1="0" x2="0" y2="1">
|
||
<stop offset="0%" stop-color="#1B7FB5"/>
|
||
<stop offset="100%" stop-color="#00D9FF"/>
|
||
</linearGradient>
|
||
<radialGradient id="pumpGlow" cx="50%" cy="50%" r="50%">
|
||
<stop offset="0%" stop-color="rgba(0,217,255,0.5)"/>
|
||
<stop offset="100%" stop-color="transparent"/>
|
||
</radialGradient>
|
||
</defs>
|
||
|
||
<!-- ============ TITLE LABELS ============ -->
|
||
<g font-family="JetBrains Mono" font-size="10" fill="#7C8B9F" letter-spacing="1">
|
||
<text x="40" y="40">P&ID · FUEL</text>
|
||
<text x="40" y="56">Rev 1.0 · Sprint 0</text>
|
||
</g>
|
||
|
||
<!-- ============ TANKS ============ -->
|
||
<!-- Tank 1 -->
|
||
<g transform="translate(80,140)">
|
||
<rect x="0" y="0" width="180" height="280" rx="10" fill="url(#tank)" stroke="#2C3E5C" stroke-width="2"/>
|
||
<rect x="6" y="68" width="168" height="206" rx="6" fill="url(#fuelFill)" opacity="0.85"/>
|
||
<rect x="6" y="64" width="168" height="8" fill="#00D9FF" opacity="0.4" filter="blur(2px)"/>
|
||
<text x="90" y="-12" text-anchor="middle" font-family="JetBrains Mono" font-size="13" font-weight="700" fill="#E6EAF0">TANK_FUEL_1</text>
|
||
<text x="90" y="320" text-anchor="middle" font-family="Inter" font-size="11" fill="#7C8B9F">Capacidad 3500 L</text>
|
||
|
||
<!-- Level meter on tank side -->
|
||
<line x1="-12" y1="0" x2="-12" y2="280" stroke="#7C8B9F" stroke-width="1"/>
|
||
<g font-family="JetBrains Mono" font-size="9" fill="#7C8B9F" text-anchor="end">
|
||
<line x1="-18" y1="0" x2="-12" y2="0"/><text x="-22" y="4">100%</text>
|
||
<line x1="-18" y1="70" x2="-12" y2="70"/><text x="-22" y="74">75%</text>
|
||
<line x1="-18" y1="140" x2="-12" y2="140"/><text x="-22" y="144">50%</text>
|
||
<line x1="-18" y1="210" x2="-12" y2="210"/><text x="-22" y="214">25%</text>
|
||
<line x1="-18" y1="280" x2="-12" y2="280"/><text x="-22" y="284">0%</text>
|
||
</g>
|
||
|
||
<!-- Level value -->
|
||
<g transform="translate(90,150)">
|
||
<rect x="-50" y="-26" width="100" height="52" rx="8" fill="rgba(4,17,31,0.85)" stroke="#00D9FF" stroke-width="1.5"/>
|
||
<text text-anchor="middle" y="0" font-family="JetBrains Mono" font-size="24" font-weight="700" fill="#F2F5F9">78%</text>
|
||
<text text-anchor="middle" y="18" font-family="Inter" font-size="10" fill="#7C8B9F">2,730 L</text>
|
||
</g>
|
||
</g>
|
||
|
||
<!-- Tank 2 -->
|
||
<g transform="translate(300,140)">
|
||
<rect x="0" y="0" width="180" height="280" rx="10" fill="url(#tank)" stroke="#2C3E5C" stroke-width="2"/>
|
||
<rect x="6" y="105" width="168" height="169" rx="6" fill="url(#fuelFill2)" opacity="0.85"/>
|
||
<rect x="6" y="101" width="168" height="8" fill="#00D9FF" opacity="0.4" filter="blur(2px)"/>
|
||
<text x="90" y="-12" text-anchor="middle" font-family="JetBrains Mono" font-size="13" font-weight="700" fill="#E6EAF0">TANK_FUEL_2</text>
|
||
<text x="90" y="320" text-anchor="middle" font-family="Inter" font-size="11" fill="#7C8B9F">Capacidad 3500 L</text>
|
||
|
||
<g transform="translate(90,170)">
|
||
<rect x="-50" y="-26" width="100" height="52" rx="8" fill="rgba(4,17,31,0.85)" stroke="#00D9FF" stroke-width="1.5"/>
|
||
<text text-anchor="middle" y="0" font-family="JetBrains Mono" font-size="24" font-weight="700" fill="#F2F5F9">64%</text>
|
||
<text text-anchor="middle" y="18" font-family="Inter" font-size="10" fill="#7C8B9F">2,240 L</text>
|
||
</g>
|
||
</g>
|
||
|
||
<!-- ============ PIPES from tanks ============ -->
|
||
<g stroke="#00D9FF" stroke-width="2.5" fill="none">
|
||
<!-- Tank 1 outlet to manifold -->
|
||
<path d="M 260 380 L 280 380 L 280 480 L 540 480" class="flow"/>
|
||
<!-- Tank 2 outlet to manifold -->
|
||
<path d="M 480 380 L 480 470 L 540 470" class="flow"/>
|
||
</g>
|
||
|
||
<!-- ============ VALVES ============ -->
|
||
<!-- Valve T1 outlet -->
|
||
<g transform="translate(260,380)">
|
||
<path d="M 0 -8 L 16 0 L 0 8 L -16 0 Z" fill="#00E08A" stroke="#04111F" stroke-width="1.5"/>
|
||
<line x1="0" y1="-10" x2="0" y2="-18" stroke="#7C8B9F" stroke-width="2"/>
|
||
<circle cx="0" cy="-22" r="4" fill="#00E08A"/>
|
||
<text x="0" y="22" text-anchor="middle" font-family="JetBrains Mono" font-size="9" fill="#7C8B9F">V_T1_OUT</text>
|
||
</g>
|
||
<!-- Valve T2 outlet -->
|
||
<g transform="translate(480,380)">
|
||
<path d="M 0 -8 L 16 0 L 0 8 L -16 0 Z" fill="#00E08A" stroke="#04111F" stroke-width="1.5"/>
|
||
<line x1="0" y1="-10" x2="0" y2="-18" stroke="#7C8B9F" stroke-width="2"/>
|
||
<circle cx="0" cy="-22" r="4" fill="#00E08A"/>
|
||
<text x="0" y="22" text-anchor="middle" font-family="JetBrains Mono" font-size="9" fill="#7C8B9F">V_T2_OUT</text>
|
||
</g>
|
||
|
||
<!-- ============ FILTER ============ -->
|
||
<g transform="translate(540,460)">
|
||
<rect x="0" y="0" width="50" height="40" rx="4" fill="#1A2B42" stroke="#00D9FF" stroke-width="2"/>
|
||
<line x1="0" y1="10" x2="50" y2="10" stroke="#7C8B9F"/>
|
||
<line x1="0" y1="20" x2="50" y2="20" stroke="#7C8B9F"/>
|
||
<line x1="0" y1="30" x2="50" y2="30" stroke="#7C8B9F"/>
|
||
<text x="25" y="55" text-anchor="middle" font-family="JetBrains Mono" font-size="9" fill="#7C8B9F">FILTER 30µm</text>
|
||
<text x="25" y="-6" text-anchor="middle" font-family="JetBrains Mono" font-size="8" fill="#00E08A">Δp 0.4 bar</text>
|
||
</g>
|
||
|
||
<!-- ============ MAIN PUMP ============ -->
|
||
<g transform="translate(660,480)">
|
||
<circle cx="0" cy="0" r="32" fill="url(#pumpGlow)" />
|
||
<circle cx="0" cy="0" r="24" fill="#1A2B42" stroke="#00D9FF" stroke-width="2.5"/>
|
||
<g class="pump-rotor">
|
||
<path d="M -16 0 L 16 0 M 0 -16 L 0 16" stroke="#00D9FF" stroke-width="3" stroke-linecap="round"/>
|
||
<circle r="4" fill="#00D9FF"/>
|
||
</g>
|
||
<text x="0" y="48" text-anchor="middle" font-family="JetBrains Mono" font-size="10" font-weight="700" fill="#F2F5F9">PUMP_MAIN</text>
|
||
<text x="0" y="62" text-anchor="middle" font-family="JetBrains Mono" font-size="9" fill="#00E08A">RUNNING · 2.8 bar</text>
|
||
</g>
|
||
|
||
<!-- Pipe pump to manifold up -->
|
||
<g stroke="#00D9FF" stroke-width="2.5" fill="none">
|
||
<path d="M 590 480 L 630 480" class="flow fast"/>
|
||
<path d="M 692 480 L 720 480 L 720 220" class="flow fast"/>
|
||
</g>
|
||
|
||
<!-- ============ MANIFOLD to engines (top) ============ -->
|
||
<g stroke="#00D9FF" stroke-width="2.5" fill="none">
|
||
<line x1="720" y1="220" x2="980" y2="220" class="flow"/>
|
||
<!-- Branch to ME_PORT -->
|
||
<line x1="780" y1="220" x2="780" y2="160" class="flow"/>
|
||
<!-- Branch to ME_STBD -->
|
||
<line x1="860" y1="220" x2="860" y2="160" class="flow"/>
|
||
<!-- Branch to GEN_1 -->
|
||
<line x1="940" y1="220" x2="940" y2="320" class="flow"/>
|
||
</g>
|
||
|
||
<!-- ============ ENGINES (consumers) ============ -->
|
||
<g transform="translate(720,80)">
|
||
<rect x="0" y="0" width="120" height="60" rx="8" fill="#0A1A2E" stroke="#00E08A" stroke-width="2"/>
|
||
<text x="60" y="22" text-anchor="middle" font-family="JetBrains Mono" font-size="13" font-weight="700" fill="#F2F5F9">ME_PORT</text>
|
||
<text x="60" y="40" text-anchor="middle" font-family="JetBrains Mono" font-size="10" fill="#00E08A">1,520 rpm · 62%</text>
|
||
<text x="60" y="54" text-anchor="middle" font-family="Inter" font-size="9" fill="#7C8B9F">Consumo 14.2 L/h</text>
|
||
</g>
|
||
<g transform="translate(800,80)">
|
||
<rect x="0" y="0" width="120" height="60" rx="8" fill="#0A1A2E" stroke="#00E08A" stroke-width="2"/>
|
||
<text x="60" y="22" text-anchor="middle" font-family="JetBrains Mono" font-size="13" font-weight="700" fill="#F2F5F9">ME_STBD</text>
|
||
<text x="60" y="40" text-anchor="middle" font-family="JetBrains Mono" font-size="10" fill="#00E08A">1,498 rpm · 58%</text>
|
||
<text x="60" y="54" text-anchor="middle" font-family="Inter" font-size="9" fill="#7C8B9F">Consumo 13.4 L/h</text>
|
||
</g>
|
||
<g transform="translate(880,340)">
|
||
<rect x="0" y="0" width="120" height="60" rx="8" fill="#0A1A2E" stroke="#FFB020" stroke-width="2"/>
|
||
<text x="60" y="22" text-anchor="middle" font-family="JetBrains Mono" font-size="13" font-weight="700" fill="#F2F5F9">GEN_1</text>
|
||
<text x="60" y="40" text-anchor="middle" font-family="JetBrains Mono" font-size="10" fill="#FFB020">1,800 rpm · 88%</text>
|
||
<text x="60" y="54" text-anchor="middle" font-family="Inter" font-size="9" fill="#7C8B9F">Consumo 16.3 L/h</text>
|
||
</g>
|
||
|
||
<!-- Engine box labels (inlet valves) -->
|
||
<g transform="translate(780,160)">
|
||
<circle r="6" fill="#00E08A" stroke="#04111F" stroke-width="1.5"/>
|
||
</g>
|
||
<g transform="translate(860,160)">
|
||
<circle r="6" fill="#00E08A" stroke="#04111F" stroke-width="1.5"/>
|
||
</g>
|
||
<g transform="translate(940,320)">
|
||
<circle r="6" fill="#00E08A" stroke="#04111F" stroke-width="1.5"/>
|
||
</g>
|
||
|
||
<!-- ============ DAY TANK ============ -->
|
||
<g transform="translate(560,320)">
|
||
<rect x="0" y="0" width="80" height="100" rx="6" fill="url(#tank)" stroke="#2C3E5C" stroke-width="2"/>
|
||
<rect x="4" y="36" width="72" height="62" rx="3" fill="url(#fuelFill)" opacity="0.85"/>
|
||
<rect x="4" y="34" width="72" height="6" fill="#00D9FF" opacity="0.4" filter="blur(1.5px)"/>
|
||
<text x="40" y="-8" text-anchor="middle" font-family="JetBrains Mono" font-size="11" font-weight="700" fill="#E6EAF0">DAY TANK</text>
|
||
<text x="40" y="118" text-anchor="middle" font-family="JetBrains Mono" font-size="11" fill="#F2F5F9">64%</text>
|
||
</g>
|
||
|
||
<!-- ============ RETURN LINE ============ -->
|
||
<g stroke="#5BC0EB" stroke-width="1.8" fill="none" stroke-dasharray="3 3" opacity="0.7">
|
||
<path d="M 720 110 L 1040 110 L 1040 510 L 280 510 L 280 410"/>
|
||
</g>
|
||
<text x="900" y="105" font-family="JetBrains Mono" font-size="9" fill="#5BC0EB">RETURN LINE</text>
|
||
|
||
<!-- ============ PRESSURE GAUGE ============ -->
|
||
<g transform="translate(660,420)">
|
||
<circle r="22" fill="#0A1A2E" stroke="#00D9FF" stroke-width="2"/>
|
||
<text text-anchor="middle" y="-4" font-family="JetBrains Mono" font-size="11" font-weight="700" fill="#F2F5F9">2.8</text>
|
||
<text text-anchor="middle" y="10" font-family="JetBrains Mono" font-size="9" fill="#7C8B9F">bar</text>
|
||
<path d="M 0 0 L 12 -8" stroke="#00D9FF" stroke-width="2" stroke-linecap="round"/>
|
||
</g>
|
||
|
||
<!-- ============ FUEL CONSUMPTION SUMMARY ============ -->
|
||
<g transform="translate(40,520)">
|
||
<rect x="0" y="0" width="280" height="120" rx="10" fill="rgba(4,17,31,0.7)" stroke="#1A2B42" stroke-width="1.5"/>
|
||
<text x="16" y="22" font-family="Inter" font-size="10" font-weight="700" fill="#7C8B9F" letter-spacing="1.5">CONSUMO TOTAL ÚLTIMA HORA</text>
|
||
<text x="16" y="64" font-family="JetBrains Mono" font-size="36" font-weight="700" fill="#F2F5F9">43.9 <tspan font-size="14" fill="#7C8B9F">L/h</tspan></text>
|
||
<line x1="16" y1="78" x2="264" y2="78" stroke="#1A2B42"/>
|
||
<g font-family="JetBrains Mono" font-size="10" fill="#7C8B9F">
|
||
<text x="16" y="98">ME_PORT 14.2</text>
|
||
<text x="100" y="98">ME_STBD 13.4</text>
|
||
<text x="186" y="98">GEN_1 16.3</text>
|
||
</g>
|
||
<text x="16" y="112" font-family="Inter" font-size="10" fill="#00E08A">Autonomía a régimen: 113 h</text>
|
||
</g>
|
||
|
||
<!-- Pulsing alarm marker (info) on filter pressure approaching limit -->
|
||
<g transform="translate(570,440)">
|
||
<circle r="12" fill="rgba(91,192,235,0.18)" stroke="#5BC0EB" stroke-width="1.5">
|
||
<animate attributeName="r" values="10;14;10" dur="2s" repeatCount="indefinite"/>
|
||
<animate attributeName="opacity" values="1;0.4;1" dur="2s" repeatCount="indefinite"/>
|
||
</circle>
|
||
<text text-anchor="middle" y="3" font-family="Inter" font-size="9" font-weight="700" fill="#5BC0EB">i</text>
|
||
</g>
|
||
</svg>
|
||
|
||
<div class="legend">
|
||
<span><span class="swatch" style="background: #00E08A;"></span> Válvula abierta</span>
|
||
<span><span class="swatch" style="background: #FF8030;"></span> Válvula cerrada</span>
|
||
<span><span class="swatch" style="background: #00D9FF;"></span> Flujo activo</span>
|
||
<span><span class="swatch" style="background: transparent; border: 1px dashed #5BC0EB;"></span> Retorno</span>
|
||
<span><span class="swatch" style="background: rgba(91,192,235,0.3); border: 1px solid #5BC0EB;"></span> Info / watch</span>
|
||
</div>
|
||
</main>
|
||
|
||
<aside class="inspector">
|
||
<div class="insp-tag">TANK_FUEL_1.LEVEL</div>
|
||
<h3 class="insp-name">Nivel tanque combustible 1</h3>
|
||
|
||
<div class="insp-value">78<span class="unit">%</span></div>
|
||
|
||
<svg class="insp-trend" viewBox="0 0 280 60" preserveAspectRatio="none">
|
||
<defs>
|
||
<linearGradient id="tArea" x1="0" y1="0" x2="0" y2="1">
|
||
<stop offset="0%" stop-color="rgba(0,217,255,0.45)"/>
|
||
<stop offset="100%" stop-color="rgba(0,217,255,0)"/>
|
||
</linearGradient>
|
||
</defs>
|
||
<path d="M 0 30 L 30 28 L 60 33 L 90 26 L 120 24 L 150 22 L 180 19 L 210 14 L 240 13 L 280 12 L 280 60 L 0 60 Z" fill="url(#tArea)"/>
|
||
<path d="M 0 30 L 30 28 L 60 33 L 90 26 L 120 24 L 150 22 L 180 19 L 210 14 L 240 13 L 280 12" stroke="#00D9FF" stroke-width="2" fill="none"/>
|
||
<circle cx="280" cy="12" r="4" fill="#00D9FF"/>
|
||
</svg>
|
||
<div style="display: flex; justify-content: space-between; font-family: var(--f-mono); font-size: 10px; color: var(--c-fog); margin-top: 4px;">
|
||
<span>-6h</span><span>-3h</span><span>now</span>
|
||
</div>
|
||
|
||
<div style="margin-top: var(--s-5);">
|
||
<div class="insp-row"><span class="k">Volumen</span><span class="v">2,730 L</span></div>
|
||
<div class="insp-row"><span class="k">Capacidad</span><span class="v">3,500 L</span></div>
|
||
<div class="insp-row"><span class="k">Range normal</span><span class="v">10 – 100%</span></div>
|
||
<div class="insp-row"><span class="k">Calidad</span><span class="v" style="color:var(--c-ok)">GOOD</span></div>
|
||
<div class="insp-row"><span class="k">Última lectura</span><span class="v">42 ms</span></div>
|
||
<div class="insp-row"><span class="k">Protocolo</span><span class="v">MODBUS_RTU</span></div>
|
||
<div class="insp-row"><span class="k">Tarjeta</span><span class="v">card_004 / AI3</span></div>
|
||
<div class="insp-row"><span class="k">Filtro</span><span class="v">MOVING_AVG · 8</span></div>
|
||
<div class="insp-row"><span class="k">Historizando</span><span class="v" style="color:var(--c-ok)">SÍ · 1s</span></div>
|
||
</div>
|
||
|
||
<div class="alarm-section">
|
||
<div class="ttl">2 alarmas configuradas</div>
|
||
<div style="margin-top: 8px; font-size: 12px; font-family: var(--f-mono); color: var(--c-sand);">
|
||
<div>LOW < 15% <span style="color:var(--c-warn)">LOW</span></div>
|
||
<div>LOW_LOW < 5% <span style="color:var(--c-emergency)">EMERGENCY</span></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div style="margin-top: var(--s-5);">
|
||
<button class="btn btn-secondary" style="width: 100%;">Abrir trend completo</button>
|
||
</div>
|
||
</aside>
|
||
|
||
<footer class="ticker">
|
||
<span class="pulse"></span>
|
||
<span>WebSocket LIVE</span>
|
||
<span class="sep">|</span>
|
||
<span>187 tags activos</span>
|
||
<span class="sep">|</span>
|
||
<span>2 alarmas</span>
|
||
<span class="tk-spacer"></span>
|
||
<span>v0.1.0.dev0 · Sprint 0</span>
|
||
</footer>
|
||
|
||
</div>
|
||
</body>
|
||
</html>
|