facelift: fleet constellation hero + Bat-Computer type/token layer
Chakra Petch site-wide (300-700) + JetBrains Mono variable, all self-hosted (CSP zero-external holds). Token layer gains the mock-exact text tiers, glass panel, cyan-tinted borders, glows, tighter radii; light 'blueprint' variants included. New Constellation.astro: the six real nodes as IC chips on dual-trace PCB paths (cyan out / magenta back, dasharray packets), radar ring on the cave hub, vias at bends - pure SVG + scoped CSS keyframes, full reduced-motion fallback. Hero rebuilt: scrim stack + masked grid over the board art, two-line gradient nameplate, typing bar cycling six real fleet facts via the external site.js (facts from src/data/fleet.ts), scroll indicator. Facts wrap, never clip.
This commit is contained in:
@@ -0,0 +1,243 @@
|
||||
---
|
||||
// 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>
|
||||
<text class="cap cap--hub" x="380" y="392" text-anchor="middle">139 apps · reconciling</text>
|
||||
|
||||
<!-- ── awake: alfred ── -->
|
||||
<circle cx="612" cy="128" r="24" fill="rgba(63,186,245,0.07)"></circle>
|
||||
<rect class="chip chip--cyan" x="595" y="111" width="34" height="34" rx="5"></rect>
|
||||
<circle class="core core--cyan pulse" cx="612" cy="128" r="4"></circle>
|
||||
<rect class="plate plate--cyan" 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>
|
||||
<text class="cap cap--dim" x="160" y="206" text-anchor="middle">standby · 33 apps known</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 ── -->
|
||||
<rect class="chip chip--cyan" x="437" y="533" width="30" height="30" rx="5"></rect>
|
||||
<circle class="core core--cyan 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>
|
||||
</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)); }
|
||||
.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)); }
|
||||
.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--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; }
|
||||
|
||||
/* radar ring off the hub */
|
||||
.ring {
|
||||
transform-box: fill-box;
|
||||
transform-origin: center;
|
||||
animation: bzRing 3.6s ease-out infinite;
|
||||
}
|
||||
|
||||
@keyframes bzDash { to { stroke-dashoffset: -260; } }
|
||||
@keyframes bzDashRev { to { stroke-dashoffset: 260; } }
|
||||
@keyframes bzPulse { 0%, 100% { opacity: 0.35; } 50% { opacity: 1; } }
|
||||
@keyframes bzRing {
|
||||
0% { transform: scale(0.5); 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>
|
||||
Reference in New Issue
Block a user