267 lines
13 KiB
Plaintext
267 lines
13 KiB
Plaintext
---
|
||
// The fleet constellation - 6 real nodes as IC chips on PCB traces.
|
||
// Pure SVG + scoped CSS keyframes (zero JS; reduced-motion turns every animation off).
|
||
// Anatomy per the design handoff: each route is TWO parallel traces (offset ±(2,-3)) -
|
||
// one carries a cyan packet outbound, the other a magenta packet inbound. Packets are
|
||
// stroke-dasharray 9/127 sliding via stroke-dashoffset. Hub = cave (56px chip, radar ring).
|
||
---
|
||
|
||
<svg
|
||
class="constellation"
|
||
viewBox="0 0 760 640"
|
||
role="img"
|
||
aria-label="Live topology of the six-node homelab fleet: hub cave reconciling alfred, robin, kate, wgirl and elfastc"
|
||
>
|
||
<defs>
|
||
<linearGradient id="lgA" x1="0" y1="0" x2="1" y2="1">
|
||
<stop offset="0" stop-color="var(--accent)"></stop>
|
||
<stop offset="1" stop-color="var(--accent-2)"></stop>
|
||
</linearGradient>
|
||
</defs>
|
||
|
||
<!-- ── PCB traces: dual parallel lines per route (out = cyan, back = magenta) ── -->
|
||
<!-- alfred -->
|
||
<g transform="translate(2,-3)">
|
||
<path class="t-glow t-cyan" d="M380 310 H460 L520 250 V180 L572 128 H595"></path>
|
||
<path class="t-base t-cyan" d="M380 310 H460 L520 250 V180 L572 128 H595"></path>
|
||
<path class="t-pkt pkt-fwd" d="M380 310 H460 L520 250 V180 L572 128 H595"></path>
|
||
</g>
|
||
<g transform="translate(-2,3)">
|
||
<path class="t-glow t-mag" d="M380 310 H460 L520 250 V180 L572 128 H595"></path>
|
||
<path class="t-base t-mag" d="M380 310 H460 L520 250 V180 L572 128 H595"></path>
|
||
<path class="t-pkt t-pkt--mag pkt-rev-slow" d="M380 310 H460 L520 250 V180 L572 128 H595"></path>
|
||
</g>
|
||
<!-- robin -->
|
||
<g transform="translate(2,-3)">
|
||
<path class="t-glow t-cyan" d="M380 310 H470 L540 380 H602 L640 420"></path>
|
||
<path class="t-base t-cyan" d="M380 310 H470 L540 380 H602 L640 420"></path>
|
||
<path class="t-pkt pkt-fwd-slow" d="M380 310 H470 L540 380 H602 L640 420"></path>
|
||
</g>
|
||
<g transform="translate(-2,3)">
|
||
<path class="t-glow t-mag" d="M380 310 H470 L540 380 H602 L640 420"></path>
|
||
<path class="t-base t-mag" d="M380 310 H470 L540 380 H602 L640 420"></path>
|
||
<path class="t-pkt t-pkt--mag pkt-rev" d="M380 310 H470 L540 380 H602 L640 420"></path>
|
||
</g>
|
||
<!-- kate (standby - dimmer) -->
|
||
<g transform="translate(2,-3)" class="standby">
|
||
<path class="t-glow t-cyan" d="M380 310 H300 L240 250 V202 L188 150 H176"></path>
|
||
<path class="t-base t-cyan" d="M380 310 H300 L240 250 V202 L188 150 H176"></path>
|
||
<path class="t-pkt t-pkt--solid pkt-fwd-slow" d="M380 310 H300 L240 250 V202 L188 150 H176"></path>
|
||
</g>
|
||
<g transform="translate(-2,3)" class="standby">
|
||
<path class="t-glow t-mag" d="M380 310 H300 L240 250 V202 L188 150 H176"></path>
|
||
<path class="t-base t-mag" d="M380 310 H300 L240 250 V202 L188 150 H176"></path>
|
||
<path class="t-pkt t-pkt--mag t-pkt--solid pkt-rev" d="M380 310 H300 L240 250 V202 L188 150 H176"></path>
|
||
</g>
|
||
<!-- wgirl (standby) -->
|
||
<g transform="translate(2,-3)" class="standby">
|
||
<path class="t-glow t-cyan" d="M380 310 H310 L244 376 V446 L214 474"></path>
|
||
<path class="t-base t-cyan" d="M380 310 H310 L244 376 V446 L214 474"></path>
|
||
<path class="t-pkt t-pkt--solid pkt-fwd" d="M380 310 H310 L244 376 V446 L214 474"></path>
|
||
</g>
|
||
<g transform="translate(-2,3)" class="standby">
|
||
<path class="t-glow t-mag" d="M380 310 H310 L244 376 V446 L214 474"></path>
|
||
<path class="t-base t-mag" d="M380 310 H310 L244 376 V446 L214 474"></path>
|
||
<path class="t-pkt t-pkt--mag t-pkt--solid pkt-rev-slow" d="M380 310 H310 L244 376 V446 L214 474"></path>
|
||
</g>
|
||
<!-- elfastc (standby) -->
|
||
<g transform="translate(3,2)" class="standby">
|
||
<path class="t-glow t-cyan" d="M380 310 V400 L452 472 V532"></path>
|
||
<path class="t-base t-cyan" d="M380 310 V400 L452 472 V532"></path>
|
||
<path class="t-pkt t-pkt--solid pkt-fwd-slow" d="M380 310 V400 L452 472 V532"></path>
|
||
</g>
|
||
<g transform="translate(-3,-2)" class="standby">
|
||
<path class="t-glow t-mag" d="M380 310 V400 L452 472 V532"></path>
|
||
<path class="t-base t-mag" d="M380 310 V400 L452 472 V532"></path>
|
||
<path class="t-pkt t-pkt--mag t-pkt--solid pkt-rev" d="M380 310 V400 L452 472 V532"></path>
|
||
</g>
|
||
|
||
<!-- vias at trace bends -->
|
||
<circle class="via via--cyan" cx="460" cy="310" r="3"></circle>
|
||
<circle class="via via--cyan" cx="520" cy="250" r="3"></circle>
|
||
<circle class="via via--cyan" cx="520" cy="180" r="3"></circle>
|
||
<circle class="via via--mag" cx="470" cy="310" r="3"></circle>
|
||
<circle class="via via--mag" cx="540" cy="380" r="3"></circle>
|
||
<circle class="via via--dim" cx="300" cy="310" r="3"></circle>
|
||
<circle class="via via--dim" cx="240" cy="250" r="3"></circle>
|
||
<circle class="via via--dim" cx="310" cy="310" r="3"></circle>
|
||
<circle class="via via--dim" cx="244" cy="376" r="3"></circle>
|
||
<circle class="via via--dim" cx="380" cy="400" r="3"></circle>
|
||
<circle class="via via--dim" cx="452" cy="472" r="3"></circle>
|
||
|
||
<!-- ── hub: cave ── -->
|
||
<circle class="ring" cx="380" cy="310" r="46" fill="none" stroke="url(#lgA)" stroke-width="1.5"></circle>
|
||
<circle cx="380" cy="310" r="46" fill="rgba(63,186,245,0.05)" stroke="rgba(63,186,245,0.3)" stroke-width="1"></circle>
|
||
<!-- pin stubs -->
|
||
<g class="pins-cyan">
|
||
<line x1="352" y1="296" x2="340" y2="296"></line><line x1="352" y1="310" x2="340" y2="310"></line>
|
||
<line x1="352" y1="324" x2="340" y2="324"></line><line x1="366" y1="282" x2="366" y2="270"></line>
|
||
<line x1="380" y1="282" x2="380" y2="270"></line><line x1="366" y1="338" x2="366" y2="350"></line>
|
||
<line x1="380" y1="338" x2="380" y2="350"></line>
|
||
</g>
|
||
<g class="pins-mag">
|
||
<line x1="408" y1="296" x2="420" y2="296"></line><line x1="408" y1="310" x2="420" y2="310"></line>
|
||
<line x1="408" y1="324" x2="420" y2="324"></line><line x1="394" y1="282" x2="394" y2="270"></line>
|
||
<line x1="394" y1="338" x2="394" y2="350"></line>
|
||
</g>
|
||
<rect class="chip chip--hub" x="352" y="282" width="56" height="56" rx="8" stroke="url(#lgA)"></rect>
|
||
<rect x="364" y="294" width="32" height="32" rx="4" fill="none" stroke="rgba(63,186,245,0.4)" stroke-width="1"></rect>
|
||
<circle class="core core--cyan pulse" cx="380" cy="310" r="5"></circle>
|
||
<rect class="plate plate--hub" x="338" y="352" width="84" height="24" rx="4"></rect>
|
||
<text class="lbl lbl--hub" x="380" y="368" text-anchor="middle">cave</text>
|
||
|
||
<!-- ── awake: alfred (Intel compute - NUC iGPU/QuickSync) ── -->
|
||
<circle cx="612" cy="128" r="24" fill="rgba(0,199,253,0.07)"></circle>
|
||
<rect class="chip chip--intel" x="595" y="111" width="34" height="34" rx="5"></rect>
|
||
<circle class="core core--intel pulse" cx="612" cy="128" r="4"></circle>
|
||
<rect class="plate plate--intel" x="576" y="152" width="72" height="20" rx="3"></rect>
|
||
<text class="lbl" x="612" y="166" text-anchor="middle">alfred</text>
|
||
|
||
<!-- ── awake: robin ── -->
|
||
<circle cx="656" cy="420" r="24" fill="rgba(232,121,249,0.07)"></circle>
|
||
<rect class="chip chip--mag" x="639" y="403" width="34" height="34" rx="5"></rect>
|
||
<circle class="core core--mag pulse-slow" cx="656" cy="420" r="4"></circle>
|
||
<rect class="plate plate--mag" x="620" y="444" width="72" height="20" rx="3"></rect>
|
||
<text class="lbl" x="656" y="458" text-anchor="middle">robin</text>
|
||
|
||
<!-- ── standby: kate ── -->
|
||
<rect class="chip chip--cyan" x="145" y="135" width="30" height="30" rx="5"></rect>
|
||
<circle class="core core--cyan pulse-slow" cx="160" cy="150" r="3.5"></circle>
|
||
<rect class="plate plate--dim" x="126" y="172" width="68" height="20" rx="3"></rect>
|
||
<text class="lbl lbl--dim" x="160" y="186" text-anchor="middle">kate</text>
|
||
|
||
<!-- ── standby: wgirl ── -->
|
||
<rect class="chip chip--mag" x="199" y="471" width="30" height="30" rx="5"></rect>
|
||
<circle class="core core--mag pulse" cx="214" cy="486" r="3.5"></circle>
|
||
<rect class="plate plate--dim" x="180" y="508" width="68" height="20" rx="3"></rect>
|
||
<text class="lbl lbl--dim" x="214" y="522" text-anchor="middle">wgirl</text>
|
||
|
||
<!-- ── standby: elfastc (Intel compute - 2× Arc B580) ── -->
|
||
<rect class="chip chip--intel" x="437" y="533" width="30" height="30" rx="5"></rect>
|
||
<circle class="core core--intel pulse-slow" cx="452" cy="548" r="3.5"></circle>
|
||
<rect class="plate plate--dim" x="412" y="570" width="80" height="20" rx="3"></rect>
|
||
<text class="lbl lbl--dim" x="452" y="584" text-anchor="middle">elfastc</text>
|
||
|
||
<!-- ── key: compute colours (right side - left edge clips on narrow heroes) ── -->
|
||
<g aria-label="compute colour key">
|
||
<rect class="core--mag" x="620" y="572" width="8" height="8" rx="2"></rect>
|
||
<text class="cap cap--key" x="634" y="580">nvidia compute</text>
|
||
<rect class="core--intel" x="620" y="592" width="8" height="8" rx="2"></rect>
|
||
<text class="cap cap--key" x="634" y="600">intel compute</text>
|
||
<rect class="key--bat" x="620" y="612" width="8" height="8" rx="2"></rect>
|
||
<text class="cap cap--key" x="634" y="620">core / services</text>
|
||
</g>
|
||
</svg>
|
||
|
||
<style>
|
||
.constellation {
|
||
display: block;
|
||
width: 100%;
|
||
height: auto;
|
||
}
|
||
|
||
/* trace layers */
|
||
.t-glow { fill: none; stroke-width: 7; }
|
||
.t-glow.t-cyan { stroke: rgba(63, 186, 245, 0.12); }
|
||
.t-glow.t-mag { stroke: rgba(232, 121, 249, 0.1); }
|
||
.standby .t-glow.t-cyan { stroke: rgba(63, 186, 245, 0.1); }
|
||
.standby .t-glow.t-mag { stroke: rgba(232, 121, 249, 0.08); }
|
||
.t-base { fill: none; stroke-width: 2; }
|
||
.t-base.t-cyan { stroke: rgba(63, 186, 245, 0.45); }
|
||
.t-base.t-mag { stroke: rgba(232, 121, 249, 0.38); }
|
||
.standby .t-base.t-cyan { stroke: rgba(63, 186, 245, 0.35); }
|
||
.standby .t-base.t-mag { stroke: rgba(232, 121, 249, 0.3); }
|
||
|
||
/* the moving packets */
|
||
.t-pkt {
|
||
fill: none;
|
||
stroke: url(#lgA);
|
||
stroke-width: 3;
|
||
stroke-linecap: round;
|
||
stroke-dasharray: 9 127;
|
||
filter: drop-shadow(0 0 6px rgba(63, 186, 245, 0.9));
|
||
}
|
||
.t-pkt--mag { filter: drop-shadow(0 0 6px rgba(232, 121, 249, 0.9)); }
|
||
.t-pkt--solid { stroke: rgba(63, 186, 245, 0.85); }
|
||
.t-pkt--solid.t-pkt--mag { stroke: rgba(232, 121, 249, 0.85); }
|
||
|
||
.pkt-fwd { animation: bzDash 8s linear infinite; }
|
||
.pkt-fwd-slow { animation: bzDash 11s linear infinite; }
|
||
.pkt-rev { animation: bzDashRev 9s linear infinite; }
|
||
.pkt-rev-slow { animation: bzDashRev 13s linear infinite; }
|
||
|
||
/* vias */
|
||
.via { fill: var(--panel-solid); stroke-width: 1; }
|
||
.via--cyan { stroke: rgba(63, 186, 245, 0.6); }
|
||
.via--mag { stroke: rgba(232, 121, 249, 0.6); }
|
||
.via--dim { stroke: rgba(126, 139, 161, 0.5); }
|
||
|
||
/* chips + cores + plates + labels */
|
||
.chip { fill: var(--panel-solid); }
|
||
.chip--hub { stroke-width: 2; filter: drop-shadow(0 0 10px rgba(63, 186, 245, 0.45)); }
|
||
.chip--cyan { stroke: var(--accent); stroke-width: 1.5; filter: drop-shadow(0 0 8px rgba(63, 186, 245, 0.55)); }
|
||
.chip--mag { stroke: var(--accent-2); stroke-width: 1.5; filter: drop-shadow(0 0 8px rgba(232, 121, 249, 0.55)); }
|
||
.chip--intel { stroke: var(--accent-intel); stroke-width: 1.5; filter: drop-shadow(0 0 8px rgba(0, 199, 253, 0.55)); }
|
||
.core--cyan { fill: var(--accent); filter: drop-shadow(0 0 6px rgba(63, 186, 245, 1)); }
|
||
.core--mag { fill: var(--accent-2); filter: drop-shadow(0 0 5px rgba(232, 121, 249, 1)); }
|
||
.core--intel { fill: var(--accent-intel); filter: drop-shadow(0 0 6px rgba(0, 199, 253, 1)); }
|
||
.pulse { animation: bzPulse 2.4s ease-in-out infinite; }
|
||
.pulse-slow { animation: bzPulse 3.4s ease-in-out infinite; }
|
||
.pins-cyan line { stroke: rgba(63, 186, 245, 0.6); stroke-width: 1.5; }
|
||
.pins-mag line { stroke: rgba(232, 121, 249, 0.6); stroke-width: 1.5; }
|
||
.plate { fill: rgba(13, 19, 34, 0.92); stroke-width: 1; }
|
||
.plate--hub { stroke: rgba(63, 186, 245, 0.4); }
|
||
.plate--cyan { stroke: rgba(63, 186, 245, 0.35); }
|
||
.plate--mag { stroke: rgba(232, 121, 249, 0.35); }
|
||
.plate--intel { stroke: rgba(0, 199, 253, 0.35); }
|
||
.plate--dim { stroke: rgba(126, 139, 161, 0.3); }
|
||
.lbl {
|
||
fill: #e8f2fb;
|
||
font-family: var(--font-mono);
|
||
font-size: 11px;
|
||
}
|
||
.lbl--hub { font-size: 12px; font-weight: 700; }
|
||
.lbl--dim { fill: #9fb0c8; }
|
||
.cap { font-family: var(--font-mono); }
|
||
.cap--hub {
|
||
fill: var(--accent);
|
||
font-size: 9.5px;
|
||
filter: drop-shadow(0 0 4px rgba(63, 186, 245, 0.7));
|
||
}
|
||
.cap--dim { fill: #5c6a82; font-size: 9px; }
|
||
.cap--key { fill: #7e8ba1; font-size: 9px; }
|
||
/* gloss bat-black with a faint gold ring - the batcave swatch for core/services */
|
||
.key--bat {
|
||
fill: #10131c;
|
||
stroke: rgba(245, 197, 24, 0.55);
|
||
stroke-width: 1;
|
||
filter: drop-shadow(0 0 4px rgba(245, 197, 24, 0.35));
|
||
}
|
||
|
||
/* radar ring off the hub */
|
||
.ring {
|
||
transform-box: fill-box;
|
||
transform-origin: center;
|
||
animation: bzRing 3.6s ease-out infinite;
|
||
}
|
||
|
||
/* dash pattern is 9+127 = a 136px period - the loop offset MUST be an exact multiple of it
|
||
(2×136 = 272) or every packet dot visibly teleports at the loop seam. */
|
||
@keyframes bzDash { to { stroke-dashoffset: -272; } }
|
||
@keyframes bzDashRev { to { stroke-dashoffset: 272; } }
|
||
@keyframes bzPulse { 0%, 100% { opacity: 0.35; } 50% { opacity: 1; } }
|
||
@keyframes bzRing {
|
||
/* start AND end at opacity 0 so the 3.6s restart never pops */
|
||
0% { transform: scale(0.5); opacity: 0; }
|
||
10% { opacity: 0.9; }
|
||
100% { transform: scale(1.7); opacity: 0; }
|
||
}
|
||
|
||
@media (prefers-reduced-motion: reduce) {
|
||
.pkt-fwd, .pkt-fwd-slow, .pkt-rev, .pkt-rev-slow, .pulse, .pulse-slow, .ring {
|
||
animation: none;
|
||
}
|
||
.ring { opacity: 0.5; }
|
||
}
|
||
</style>
|